using System;
using System.Collections.Generic;
using BrainTechLLC;
using System.Text;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Net.Sockets;
using System.ComponentModel;
using System.Reflection;
using BrainTechLLC.ThreadSafeObjects;

namespace Mud.EmlenMudMain
{
    [Serializable]
    public class OldSchool
    {
        public OldSchool() { }

        public void fread_clan_old_format(StreamReader sr, int vnum)
        {
            ClanData clan = new ClanData();
            clan.VnumClan = vnum;
            clan.ClanAlignment = 0;
            clan.ClanLeader = "";
            clan.MinimumLevelRequiredToJoin = 0;
            clan.RoomVnumClanhouseStart = 0;
            clan.ClanMemberNames.Clear();
            char[] spc = new char[1];
            spc[0] = ' ';

            while (sr.EndOfStream == false)
            {
                string szLine = sr.ReadLine().Trim();
                if (szLine == "End")
                {
                    EmlenMud.WorldTemplates.AllClans.Add(clan);
                    return;
                }
                string[] rgsz = szLine.Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);
                string szWord = rgsz[0];

                if (szWord == "Alignment") { clan.ClanAlignment = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "CMember")
                {
                    clan.ClanMemberNames.Add(rgsz[1].TrimEnd('~'));
                    continue;
                }
                if (szWord == "Leader")
                {
                    clan.ClanLeader = rgsz[1].TrimEnd('~');
                    continue;
                }
                if (szWord == "MStartV") { clan.RoomVnumClanhouseStart = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Minlev") { clan.MinimumLevelRequiredToJoin = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Name")
                {
                    clan.Name = new NameAndDescription() { Name = rgsz[1].TrimEnd('~'), FriendlyUniqueName = rgsz[1].TrimEnd('~') };
                    continue;
                }
            }
        }
        public void fread_clan_2_old_format(StreamReader sr, int vnum)
        {
            ClanData clan = new ClanData();
            clan.VnumClan = vnum;
            clan.ClanAlignment = 0;
            clan.ClanLeader = "";
            clan.Name = new NameAndDescription() { Name = "" };
            clan.MinimumLevelRequiredToJoin = 0;
            clan.RoomVnumClanhouseStart = 0;
            clan.ClanMemberNames.Clear();
            char[] spc = new char[1];
            spc[0] = ' ';

            while (sr.EndOfStream == false)
            {
                string szLine = sr.ReadLine().Trim();
                if (szLine == "End")
                {
                    EmlenMud.WorldTemplates.AllSects.Add(clan);
                    return;
                }
                string[] rgsz = szLine.Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);
                string szWord = rgsz[0];

                if (szWord == "Alignment") { clan.ClanAlignment = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "CMember")
                {
                    clan.ClanMemberNames.Add(rgsz[1].TrimEnd('~'));
                    continue;
                }
                if (szWord == "Leader")
                {
                    clan.ClanLeader = rgsz[1].TrimEnd('~');
                    continue;
                }
                if (szWord == "MStartV") { clan.RoomVnumClanhouseStart = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Minlev") { clan.MinimumLevelRequiredToJoin = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Name")
                {
                    clan.Name = new NameAndDescription() { Name = rgsz[1].TrimEnd('~'), FriendlyUniqueName = rgsz[1].TrimEnd('~') };
                    continue;
                }
            }
        }

        public void load_random_pops_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\random.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading random.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            string szLine = sr.ReadLine().Trim();
            char[] spc = new char[1];
            spc[0] = ' ';
            ObjectPop randpop = null;
            while (szLine != "END" && szLine != "#END" && sr.EndOfStream == false)
            {
                string[] rgsz = szLine.Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);
                string szWord = rgsz[0];
                if (szWord == "OBJ")
                {
                    if (randpop != null)
                    {
                        EmlenMud.WorldTemplates.rgObjRandPopInfo.Add(randpop);
                    }
                    randpop = new ObjectPop();
                    randpop.ObjectVnum1 = Convert.ToInt32(rgsz[1]);
                }
                else if (szWord == "PCT")
                {
                    randpop.Percent = (double)(Convert.ToInt32(rgsz[1])) / (double)10.0;
                }
                else if (szWord == "ADDM")
                {
                    int mvnum = Convert.ToInt32(rgsz[1]);
                    randpop.Pops_on_mob_vnums.Add(mvnum);
                    if (EmlenMud.WorldTemplates.AllMobPrototypes.ContainsKey(mvnum) == true)
                    {
                        MobPrototype mp = EmlenMud.WorldTemplates.AllMobPrototypes[mvnum];
                        // Allow a quick way to determine if a mob prototype has any
                        // random pops associated with it
                        if (mp.random_pop_obj_vnums == null) mp.random_pop_obj_vnums = new List<long>();
                        if (mp.random_pop_obj_vnums.Contains(randpop.ObjectVnum1) == false)
                            mp.random_pop_obj_vnums.Add(randpop.ObjectVnum1);
                    }
                }

                szLine = sr.ReadLine().Trim();
            }

            if (randpop != null)
            {
                EmlenMud.WorldTemplates.rgObjRandPopInfo.Add(randpop);
            }

            sr.Close();
        }


        public void load_topten_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\topten.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading topten.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);

            for (int k = 0; k < 10; k++)
            {
                EmlenMud.WorldTemplates.topten.Topten_name[k] = "Free-Slot";
                EmlenMud.WorldTemplates.topten.Topten_warpoints[k] = 0;
                EmlenMud.WorldTemplates.topten.Topten_good[k] = true;
            }

            for (int k = 0; k < 10; k++)
            {
                EmlenMud.WorldTemplates.topten.Topten_name[k] = sr.ReadLine().Trim();
                EmlenMud.WorldTemplates.topten.Topten_warpoints[k] = Convert.ToInt32(sr.ReadLine().Trim());
                EmlenMud.WorldTemplates.topten.Topten_good[k] = Convert.ToInt32(sr.ReadLine().Trim()) == 1 ? true : false;
            }

            sr.Close();
        }
        public void load_rating_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\rating.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading rating.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);

            for (int k = 0; k < 10; k++)
            {
                EmlenMud.WorldTemplates.ratings.Rating_name[k] = "Free-Slot";
                EmlenMud.WorldTemplates.ratings.Rating_rating[k] = 0;
                EmlenMud.WorldTemplates.ratings.Rating_good[k] = true;
            }

            for (int k = 0; k < 10; k++)
            {
                EmlenMud.WorldTemplates.ratings.Rating_name[k] = sr.ReadLine().Trim();
                EmlenMud.WorldTemplates.ratings.Rating_rating[k] = Convert.ToInt32(sr.ReadLine().Trim());
                EmlenMud.WorldTemplates.ratings.Rating_good[k] = Convert.ToInt32(sr.ReadLine().Trim()) == 1 ? true : false;
            }

            sr.Close();
        }
        public void load_bansites_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\bansite.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading bansite.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            string szLine = sr.ReadLine().Trim();
            while (szLine != "END" && sr.EndOfStream == false)
            {
                string szNewB = sr.ReadLine().Trim();
                if (szNewB == "END") break;
                if (szNewB[0] == '1') EmlenMud.WorldTemplates.nbansite(szLine);
                else EmlenMud.WorldTemplates.bansite(szLine);
                szLine = sr.ReadLine().Trim();
            }

            sr.Close();
        }
        public void load_limited_old_format(int vnum)
        {
            FileStream fs = null;
            string szPath = EmlenMud.HostPathnameToMudDirectory + "\\limited\\" + vnum;
            if (File.Exists(szPath) == true)
            {
                try
                {
                    fs = new FileStream(szPath, FileMode.Open, FileAccess.Read);
                }
                catch (IOException ex) { EmlenMud.LogError("Error reading " + szPath, ex, LogType.Always); return; }

                StreamReader sr = new StreamReader(fs);
                EmlenMud.WorldTemplates.LimitedItems.Limited_array[vnum] = Convert.ToInt32(sr.ReadLine().Trim());

                sr.Close();
            }
        }
        public void load_clans_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\pclans.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading pclans.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            string szWord = "";
            while (szWord != "DONE" && sr.EndOfStream == false)
            {
                int vnum;
                char letter = ' ';
                while (letter != '#' && sr.EndOfStream == false) letter = (char)sr.Read();
                if (letter != '#')
                {
                    EmlenMud.LogError("Load_clan: '#' not found.", null, LogType.WorldError);
                    return;
                }

                vnum = Convert.ToInt32(sr.ReadLine().Trim());
                if (vnum == 0) break;

                fread_clan_old_format(sr, vnum);
                // no rgObjectsStored for now: HEREHERE: if (vnumClan > 0) fread_clan_storage(vnumClan);				
            }

            sr.Close();
        }
        public void load_clans_2_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\pclans2.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading pclans2.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            string szWord = "";
            while (szWord != "DONE" && sr.EndOfStream == false)
            {
                int vnum;
                char letter = ' ';
                while (letter != '#' && sr.EndOfStream == false) letter = (char)sr.Read();
                if (letter != '#')
                {
                    EmlenMud.LogError("Load_clan: '#' not found.", null, LogType.WorldError);
                    return;
                }

                vnum = Convert.ToInt32(sr.ReadLine().Trim());
                if (vnum == 0) break;

                fread_clan_2_old_format(sr, vnum);
            }
            sr.Close();
        }
        public void load_playerbase_old_format()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\pbase.dat", FileMode.Open, FileAccess.Read);
            }
            catch (Exception ex) { EmlenMud.LogError("Error reading pbase.dat: ", ex, LogType.Always); return; }

            if (fs == null) return;
            StreamReader sr = new StreamReader(fs);
            string szLine = sr.ReadLine().Trim();
            while (szLine != "END" && sr.EndOfStream == false)
            {
                PlayerbaseData pd = new PlayerbaseData();
                pd.PlayerName = szLine;
                string szEmail = sr.ReadLine().Trim();
                if (szEmail == "END") break;
                pd.Email_address = szEmail;
                string szLastLoginMeaningless = sr.ReadLine().Trim();
                if (szLastLoginMeaningless == "END") break;
                pd.Player_last_login = DateTime.Now;
                szLine = sr.ReadLine().Trim();
                pd.Player_good = Convert.ToInt32(szLine) == 0 ? false : true;
                szLine = sr.ReadLine().Trim();
                pd.Player_level = Convert.ToInt32(szLine);
                szLine = sr.ReadLine().Trim();
                pd.Player_nodelete = Convert.ToInt32(szLine);
                szLine = sr.ReadLine().Trim();
            }

            sr.Close();
        }

        public List<Spell> load_spells_old_format(StreamReader sr)
        {
            List<Spell> rg = new List<Spell>(32);
            char[] spc = new char[1];
            spc[0] = ' ';

            string szLine = sr.ReadLine().Trim();
            Spell spell = null;

            while (szLine != "END" && szLine != "#END" && sr.EndOfStream == false)
            {
                if (szLine == "SPELL" || szLine == "#SPELL")
                {
                    if (spell != null)
                    {
                        if (spell.Vals[0] == -9)
                            spell.Vals[0] = 0;

                        rg.Add(spell);
                    }
                    spell = new Spell();
                }
                else
                {
                    string[] rgsz = szLine.Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);
                    string szWord = rgsz[0];

                    if (szWord == "Slot") spell.Slot = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Gsn") spell.Gsn = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "SType") spell.SpellType = (SpellTargets)Convert.ToInt32(rgsz[1]);
                    else if (szWord == "SBits") spell.SpellBits = (SpellFlags)Convert.ToInt32(rgsz[1]);
                    else if (szWord == "BitT")
                    {
                        Int64 i64 = Convert.ToInt64(rgsz[1]);
                        i64 = i64 << 32;
                        spell.Bitvector = spell.Bitvector | (long)i64;
                    }
                    else if (szWord == "Sname") spell.Name = new NameAndDescription() { Name = rgsz[1].TrimEnd('~'), FriendlyUniqueName = rgsz[1].TrimEnd('~') };
                    else if (szWord == "SFname") spell.SecondaryName = rgsz[1].TrimEnd('~');
                    else if (szWord == "SLev") spell.SpellLevel = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Noun") spell.NounDamage = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2C1") spell.ActToCh1 = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2V1") spell.ActToVict1 = rgsz[1].TrimEnd('~');
                    else if (szWord == "Locat") spell.Location = (StatTypes)Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Linkd") spell.LinkedTo = rgsz[1].TrimEnd('~');
                    else if (szWord == "Durat") spell.Duration = rgsz[1].TrimEnd('~');
                    else if (szWord == "Modif") spell.Modifier = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2C2") spell.ActToCh2 = rgsz[1].TrimEnd('~');
                    else if (szWord == "Pr1") spell.Prereq1 = rgsz[1].TrimEnd('~');
                    else if (szWord == "Pr2") spell.Prereq2 = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2V2") spell.ActToVict2 = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2NV1") spell.ActToNotvict1 = rgsz[1].TrimEnd('~');
                    else if (szWord == "A2NV") spell.ActToNotvict2 = rgsz[1].TrimEnd('~');
                    else if (szWord == "BitVe")
                    {
                        spell.Bitvector = (long)Convert.ToInt64(rgsz[1]);
                    }
                    else if (szWord == "Dam") spell.Damage = rgsz[1].TrimEnd('~');
                    else if (szWord == "Mana") spell.Mana = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "ManaT") spell.Mana_type = (ManaType)Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CastT") spell.Casting_time = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Pos") spell.PositionRequired = (CharPosition)Convert.ToInt32(rgsz[1]);
                    else if (szWord == "WearO") spell.WearOffMsg = rgsz[1].TrimEnd('~');
                    else if (szWord == "CrObj") spell.CreatesObj = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV1") spell.Vals[0] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV2") spell.Vals[1] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV3") spell.Vals[2] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV4") spell.Vals[3] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV5") spell.Vals[4] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV6") spell.Vals[5] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV7") spell.Vals[6] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV8") spell.Vals[7] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV9") spell.Vals[8] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "CrV10") spell.Vals[9] = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Minint") spell.MinInt = Convert.ToInt32(rgsz[1]);
                    else if (szWord == "Minwis") spell.MinWis = Convert.ToInt32(rgsz[1]);
                }
                szLine = sr.ReadLine().Trim();
            }

            if (spell != null)
            {
                if (spell.Vals[0] == -9) spell.Vals[0] = 0;

                rg.Add(spell);
            }

            return rg;
        }


        // OLD CODE to PORT: conflict.dat  -- oops, may already be ported

        //string good;
        //string evil;

        //void 
        //read_conflict_data (void)
        //{
        //  FILE *fp;
        //  char t[STD_LENGTH];
        //  if ((fp = fopen ("conflict.dat", "r")) == NULL)
        //    {
        //      fprintf (stderr, "Could not open conflict.dat!\n");
        //      exit (5);
        //    }
        //  for (;;)
        //    {
        //      strcpy (t, fread_word (fp));
        //      if (!str_cmp (t, "END"))
        //   break;
        //      if (!str_prefix ("#", t))
        //   {
        //     fread_to_eol (fp);
        //     continue;
        //   }
        //      if (!str_cmp (t, "GOOD"))
        //   {
        //     good = str_dup (fread_word (fp));
        //     continue;
        //   }
        //      if (!str_cmp (t, "EVIL"))
        //   {
        //     evil = str_dup (fread_word (fp));
        //     continue;
        //   }
        //    }
        //  fclose (fp);
        //  return;
        //}


    }

    public partial class EmlenMud //: IEmlenMud
    {
        public static int top_ed = 1;
        private static bool fUsePortListener = false;
        private static int nListenOnPortInternal = 4443;
        private static bool fRequestShutdown = false;
        private static bool fPerformSkillWipe = false;
        private static bool fPerformEqWipe = false;
        private static PersistentWorldData WorldTemplateData = new PersistentWorldData();
        private static DynamicWorldData DynamicWorldData = new DynamicWorldData();
        private static IListenerThread incomingConnectionThread;
        private static RandomNumbers randomNumGenerator = new RandomNumbers();
        private static Constants constantsInternal = new Constants();
        //private static AddOnModuleSupport.IAddOnModules modules;
        private static IMudStats gameStats;
        private static EmlenMudEngine.IEmlenMudEngine hstWebEngine;
        private static string szHostPathname = string.Empty;//Application.StartupPath;

        [Category("Data Storage"), DescriptionAttribute("Use Old File Formats Exclusively for loading and saving of data")]
        public static DataStorageFormatTypes UseDataStorageType
        {
            get { return MiscConstants.DataStorageFormat; }
        }

        [Category("Bootup Options"), DescriptionAttribute("Open up a socket to accept telnet connections")]
        public static bool UseSocketToListenForConnections
        {
            get { return fUsePortListener; }
            set { fUsePortListener = value; }
        }

        [Category("Bootup Options"), DescriptionAttribute("Use this port to listen for incoming connections")]
        public static int AcceptIncomingConnectionsOnPort
        {
            get { return nListenOnPortInternal; }
            set
            {
                if (value == 0)
                {
                    UseSocketToListenForConnections = false;
                }
                else
                {
                    UseSocketToListenForConnections = true;
                    nListenOnPortInternal = value;
                }
            }
        }

        [Category("Bootup Options"), DescriptionAttribute("Request an immediate shutdown of the game")]
        public static bool RequestShutdown
        {
            get { return fRequestShutdown; }
            set { if (fRequestShutdown == false && value == true) { MudRunning = false; } }
        }

        [Category("Bootup Options"), DescriptionAttribute("Perform a skill wipe instead of booting the game")]
        public static bool PerformSkillwipeThisBootup
        {
            get { return fPerformSkillWipe; }
            set { fPerformSkillWipe = value; }
        }

        [Category("Bootup Options"), DescriptionAttribute("Perform an equipment wipe instead of booting the game")]
        public static bool PerformEquipmentWipeThisBootup
        {
            get { return fPerformEqWipe; }
            set { fPerformEqWipe = value; }
        }

        [Category("Bootup Options"), DescriptionAttribute("The local port number accepting incoming connections")]
        public static int ListeningOnPort { get { return nListenOnPortInternal; } }


        [Category("Dynamic World Data"), DescriptionAttribute("")]
        public static DynamicWorldData DynamicWorld
        {
            get { return DynamicWorldData; }
            set { DynamicWorldData = value; }
        }

        [Category("Template / Prototype World Data"), DescriptionAttribute("")]
        public static PersistentWorldData WorldTemplates
        {
            get { return WorldTemplateData; }
            set { WorldTemplateData = value; }
        }

        [Category("Template / Prototype World Data"), DescriptionAttribute("")]
        public static PersistentWorldData AccessWorldTemplates
        {
            get { return WorldTemplateData; }
            set { WorldTemplateData = value; }
        }

        [Category("Mud Status"), DescriptionAttribute("If set to false, the mud will gracefully stop accepting incoming connections, save everything, and then shut down.")]
        public static bool MudRunning
        {
            get { return (fRequestShutdown == false); }
            set
            {
                if (value == false)
                {
                    if (incomingConnectionThread != null)
                    {
                        // Stop accepting incoming connections
                        incomingConnectionThread.FStop = true;
                    }

                    // Stop all game looping and processing, etc
                    fRequestShutdown = true;

                    // Quickly save all players
                    for (int i = 0; i < DynamicWorld.AllPlayers1.Count; i++)
                    {
                        try { CharacterData ch = (CharacterData)DynamicWorld.AllPlayers1[i]; ch.SaveCharToDisk(); }
                        catch (Exception ex) { LogError("Could not save player to disk on game exit", ex, LogType.Always); }
                    }

                    try { NoteData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving notes", ex, LogType.Always); }
                    try { HelpData.SaveAllHelpTopics(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving help topics", ex, LogType.Always); }
                    //try { BrainTechLLC.AreaData.AreaList.SaveAllAreas(1); }
                    //catch (Exception ex) { LogError("Shutdown: Error saving area list", ex, LogType.Always); }
                    try { ClanData.Save(1, 1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving clans", ex, LogType.Always); }
                    try { ClanData.Save(2, 1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving clans2", ex, LogType.Always); }
                    try { TopTenData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving topten", ex, LogType.Always); }
                    try { RatingData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving rating data", ex, LogType.Always); }
                    //OutputMessage("Loading boats...");
                    //load_boats ();
                    try { PlayerbaseData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving playerbase data", ex, LogType.Always); }
                    try { BanData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving bandata", ex, LogType.Always); }
                    try { Spell.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving spells and skills", ex, LogType.Always); }
                    try { ObjectPop.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving random pops", ex, LogType.Always); }
                    try { SocialData.Save(1); }
                    catch (Exception ex) { LogError("Shutdown: Error saving socials", ex, LogType.Always); }
                    // TODO: can't write out power.dat yet... NYI
                    //try { PowerData.Save(1); }
                    //catch (Exception ex) { LogError("Shutdown: Error saving power data", ex, LogType.Always); }          

                    try
                    {
                        if (incomingConnectionThread.Thrd != null)
                        {
                            incomingConnectionThread.Thrd.Abort();
                        }
                    }
                    catch (Exception ex)
                    {
                        OutputMessage("Error Message aborting incoming connection thread: " + ex.Message);
                    }
                    EmlenMud.ClearEmlenMudData();
                }
                else { fRequestShutdown = false; }
            }
        }

        /// <summary>
        /// Creates a new instance of an EmlenMud virtual world
        /// </summary>
        public EmlenMud()
        {
            rgMessageQueue = new ThreadSafeQueue<LogEntry>();
            randomNumberGenerator = new RandomNumbers();
            constants = new Constants();
            gameStats = new MudStats();
        }


        #region "Loading and saving of the old format data files"
        public static OldSchool oldschool = new OldSchool();
        public static OldSchoolObjPrototypes oldschoolOP = new OldSchoolObjPrototypes();
        public static OldSchoolRooms oldschoolRoom = new OldSchoolRooms();
        public static OldSchoolAreas oldschoolArea = new OldSchoolAreas();
        public static OldSchoolMobPrototyes oldschoolMP = new OldSchoolMobPrototyes();

        public static void readPowerDat()
        {
            PowerData pwr = new PowerData();
            pwr.readPowerDat(HostPathnameToMudDirectory);
            WorldTemplates.pow = (IPowerData)pwr;
        }

        public static OldSchool Oldschool
        {
            get { return oldschool; }
            set { oldschool = value; }
        }

        public static OldSchoolObjPrototypes OldschoolOP
        {
            get { return oldschoolOP; }
            set { oldschoolOP = value; }
        }
        public static OldSchoolRooms OldschoolRoom
        {
            get { return oldschoolRoom; }
            set { oldschoolRoom = value; }
        }
        public static OldSchoolAreas OldschoolArea
        {
            get { return oldschoolArea; }
            set { oldschoolArea = value; }
        }
        public static OldSchoolMobPrototyes OldschoolMP
        {
            get { return oldschoolMP; }
            set { oldschoolMP = value; }
        }
        #endregion


        public static IListenerThread IncomingConnectionThread
        {
            get { return incomingConnectionThread; }
            set { incomingConnectionThread = value; }
        }

        public static RandomNumbers randomNumberGenerator { get { return randomNumGenerator; } set { randomNumGenerator = value; } }


        [Category("Game Constants"), DescriptionAttribute("")]
        public static Constants constants { get { return constantsInternal; } set { constantsInternal = value; } }

        //public static AddOnModuleSupport.IAddOnModules Modules
        //{
        //    get { return modules; }
        //    set { modules = value; }
        //}

        public static ThreadSafeQueue<LogEntry> rgMessageQueue;

        public static IMudStats GameStats
        {
            get { return gameStats; }
            set { gameStats = value; }
        }

        public void EnqueueMessage(string szError, Exception ex, LogType ltype)
        {
            if (hostWebEngine != null)
            {
                LogEntry logEntry = new LogEntry();
                logEntry.SetLogEntry(ltype, ex, szError);

                rgMessageQueue.Enqueue(logEntry);
                if (rgMessageQueue.Count > 1000)
                {
                    // Write to disk?
                    rgMessageQueue.Clear();
                }

                logEntry = new LogEntry();
                logEntry.SetLogEntry(ltype, ex, szError);
                hostWebEngine.EnqueueMessageFromGame(logEntry);
            }
            else
            {
#if NO_SILVERLIGHT
                if (ex == null)
                {
                    Debug.WriteLine(Enum.Format(typeof(LogType), ltype, "G") + " : " + szError);
                }
                else
                {
                    Debug.WriteLine(Enum.Format(typeof(LogType), ltype, "G") + " : " + szError + " (Exception: " + ex.Message + ")");
                }
#endif
            }
        }

        public static void OutputMessage(string sz)
        {
#if NO_SILVERLIGHT
            GlobalLogger.Log("Message", sz, BrainTechLLC.ThreadSafeObjects.LogSeverity.Information);
#endif
            //EnqueueMessage(sz, null, LogType.Message);
        }

        //public virtual void LogError(string szError, Exception ex, LogType ltype)
        //{
        //    EnqueueMessage(szError, ex, ltype);
        //}

        public static void LogError(string szError, Exception ex, LogType ltype)
        {
#if NO_SILVERLIGHT
            GlobalLogger.Log(ex, szError, BrainTechLLC.ThreadSafeObjects.LogSeverity.Critical, true);
#endif
        }

        public static double RandDoubleBetween(double d1, double d2) { return randomNumberGenerator.RandDoubleBetween(d1, d2); }
        public static int RandIntBetween(int i1, int i2) { return randomNumberGenerator.RandIntBetween(i1, i2); }
        public static int Fuzzy(int n, int nPercent) { return randomNumberGenerator.Fuzzy(n, nPercent); }

        public void Initialize()
        {
            oldschool = new OldSchool();
            oldschoolArea = new OldSchoolAreas();
            oldschoolOP = new OldSchoolObjPrototypes();
            oldschoolRoom = new OldSchoolRooms();
            oldschoolMP = new OldSchoolMobPrototyes();
            WorldTemplates = new PersistentWorldData();
            DynamicWorld = new DynamicWorldData();
            //modules = new AddOnModules(this);
        }

        public static EmlenMudEngine.IEmlenMudEngine hostWebEngine
        {
            get { return hstWebEngine; }
            set { hstWebEngine = value; }
        }

        public static string HostPathnameToMudDirectory
        {
            get { return szHostPathname; }
            set { szHostPathname = value; }
        }


        public virtual void RegisterDynamicModules()
        {
            // modules.RegisterDynamicModule("ExampleAddonModule.dll", "Mud.EmlenMudMain.Modules.ExampleAddonModule.ExampleAddon");
        }

        public virtual void InterpretCommandLineArguments(string[] args)
        {
            if (args.Length > 0)
            {
                string szArg = args[0];
                if (szArg[0] < '1' || szArg[0] > '9')
                {
                    OutputMessage(szArg + "\n");
                    fPerformEqWipe = (szArg == "Equipmentwipe") ? true : false;
                    fPerformSkillWipe = (szArg == "Skillwipe") ? true : false;
                }
                else
                {
                    nListenOnPortInternal = Convert.ToInt32(szArg);
                }
            }

            if (nListenOnPortInternal > 10000)
            {
                nListenOnPortInternal -= 10000;
                DynamicWorld.IsBuilderPort = true;
            }
        }

        public virtual void Bootup()
        {
            RegisterDynamicModules();
            string szErr = LoadAndPrepareGame();
        }

        public virtual bool PerformSkillOrEquipmentWipes()
        {
            //if (fPerformEqWipe) { EquipmentAndSkillWipe.DoEquipmentWipe(this); return true; }
            //if (fPerformSkillWipe) { EquipmentAndSkillWipe.DoSkillWipe(this); return true; }
            return false;
        }



        public virtual void AcceptPlayersAndRunTheGame()
        {
            if (UseSocketToListenForConnections == true)
            {
                //incomingConnectionThread = new ListenerThread(this);
                //incomingConnectionThread.BeginListening();
                OutputMessage("Now accepting connections on port " + ListeningOnPort.ToString() + ".");
            }

            Thread mainGameLoopThread = new Thread(new ThreadStart(MainGameLoop));
            mainGameLoopThread.IsBackground = false;

            try
            {
                mainGameLoopThread.Start();
            }
            catch (Exception ex)
            {
                LogError("Main Game Loop Error", ex, LogType.Always | LogType.WorldError);
                hostWebEngine.RegisterError(ex.Message);
            }
        }


        public static void MainGameLoop()
        {
            DateTime dtNow = DateTime.Now;
            DynamicWorld.CurrentTime.SetTimeInfo(dtNow);
            DynamicWorld.LastCombatRound.SetTimeInfo(dtNow);

            while (!fRequestShutdown)
            {
                Thread.Sleep(40);
                DateTime dtRightNow = DateTime.Now;
                DynamicWorld.CurrentTime.SetTimeInfo(dtRightNow);

                // Handle new connections, etc
                //    for (int i = DynamicWorld.RgDescriptors.Count - 1; i >= 0; i--)
                //    {
                //        DescriptorData dd = (DescriptorData)DynamicWorld.RgDescriptors[i];
                //        if (hostWebEngine != null)
                //        {
                //            DateTime dt = hostWebEngine.GetLastUserCommunication(dd.guid);
                //            TimeSpan ts = dtRightNow.Subtract(dt);
                //            if (ts.TotalSeconds > GameTiming.SecondsBeforeConsideredLinkless)
                //            {
                //                if (dd.character != null)
                //                {
                //                    dd.character.DisplayLostLink();
                //                    dd.send_text("Your connection has slowed considerably or you have lost link...\n\r");
                //                    hostWebEngine.RemoveUser(dd);
                //                    continue;
                //                }
                //            }
                //        }

                //        if (dd.ConnectionNeedsClosing == true)
                //        {
                //            if (dd.TcpConnection != null)
                //            {
                //                try { dd.TcpConnection.Client.Shutdown(SocketShutdown.Both); }
                //                catch (Exception ex) { LogError("Trying to close connection", ex, LogType.NotSerious); }
                //                try { dd.TcpConnection.Client.Close(); }
                //                catch { }
                //                try { dd.TcpConnection.Close(); }
                //                catch (Exception ex) { LogError("Trying to close connection (2)", ex, LogType.NotSerious); }
                //            }

                //            DynamicWorld.RgDescriptors.RemoveAt(i);
                //            if (dd.EmlenMud.hostWebEngine != null)
                //            {
                //                hostWebEngine.QuittingGame(dd);
                //            }

                //            dd = null;
                //            continue;
                //        }

                //        if (dd.UsingInterface != InterfaceType.HTML && dd.TcpConnection != null)
                //        {
                //            // Handle socket-level communication
                //            if (dd.TcpConnection.Connected == true)
                //            {
                //                dd.CheckBytesIncoming();
                //                dd.SendBytesOutgoing();
                //            }
                //        }

                //        // Handle the user's command, given their current connection state
                //        if (ConnectionStateHandler.HandleUserInput(dd) == false)
                //        {
                //            // Connection was forcibly closed (by us, most likely)
                //            dd.ConnectionNeedsClosing = true;
                //        }
                //    }

                //    if (DynamicWorld.RgDescriptors.Count > gameStats.maxSimultaneousConnections)
                //        gameStats.maxSimultaneousConnections = DynamicWorld.RgDescriptors.Count;

                //    if (DynamicWorld.LastCombatRound.ElapsedTime.TotalSeconds > GameTiming.SecondsBetweenEachCombatRound)
                //    {
                //        DynamicWorld.LastCombatRound.SetTimeInfo(DateTime.Now);
                //        DynamicWorld.CombatTick();
                //    }
            }

            if (incomingConnectionThread != null)
            {
                incomingConnectionThread.FStop = true;
            }

            OutputMessage("Normal termination of game.");
        }

        public static string LoadAndPrepareGame()
        {
            bool fOldFormat = true; // TODO false;
            string szAreaList = AreaList.LoadAreaList(1, ref fOldFormat);
            if (szAreaList[0] == '!') return szAreaList;

            if (fOldFormat == true)
            {
                oldschoolArea.LoadOldFormatAreasMobsObjectsEtc(szHostPathname + "\\" + MiscConstants.AREA_DIR + "\\");
                if (MiscConstants.DataStorageFormat != DataStorageFormatTypes.OldTextFileFormat)
                {
                    HelpData.SaveAllHelpTopics(1);
                    //AreaList.SaveAllAreas(1);
                }
            }
            else
            {
                // HEREHERE ((AreaList)WorldTemplates.arealist).LoadAllAreas();
                HelpData.LoadAllHelpTopics(1);
            }

            //free_arena ();
            DynamicWorld.LinkAllRoomsByExits();

            OutputMessage("Loading notes...");
            NoteData.Load(1);

            OutputMessage("Loading clans...");
            ClanData.Load(1, 1);

            OutputMessage("Loading clans 2...");
            ClanData.Load(2, 1);

            OutputMessage("Loading topten...");
            TopTenData.Load(1);

            OutputMessage("Loading ratings...");
            RatingData.Load(1);

            //OutputMessage("Loading boats...");
            //load_boats ();

            OutputMessage("Loading playerbase into memory...");
            PlayerbaseData.Load(1);

            OutputMessage("Loading bansites...");
            BanData.Load(1);

            OutputMessage("Loading score.dat and sh_score.dat...");
            WorldTemplates.read_score();
            WorldTemplates.read_sh_score();

            OutputMessage("Loading all spells and skills...");
            Spell.Load(1);
            WorldTemplates.InsertBasicSkills();

            OutputMessage("Placing all commands in the hash table...");
            MudCommands.RegisterAllCommands();

            OutputMessage("Reading commands.dat for command level overrides...");
            // read_command_levels();
            OutputMessage("Loading random pops...");
            ObjectPop.Load(1);

            OutputMessage("Loading socials...");
            SocialData.Load(1);

            OutputMessage("Loading power.dat...");
            readPowerDat();

            OutputMessage("Performing complete world repop...");
            DynamicWorld.reset_world();

            //ModuleResponse modResp = modules.HandleMudBootupAction();
            //if ((modResp & ModuleResponse.CatastrophicFailure) != 0)
            //{
            //    return "Module load returned catastrophic failure!";
            //}

            return "";
        }

        public static void ClearEmlenMudData()
        {
            DynamicWorld = null;
            WorldTemplates = null;
            oldschool = null;
            randomNumberGenerator = null;
            constants = null;
            //modules = null;
            GC.Collect();
        }

        /// <summary>
        /// Saves all critical (and only critical) data -- first players,
        /// then the topten list, then rating, then the playerbase list
        /// </summary>
        public static void SaveCriticalInfoOnCrash()
        {
            // Quickly save all players
            for (int i = 0; i < DynamicWorld.AllPlayers1.Count; i++)
            {
                try { CharacterData ch = (CharacterData)DynamicWorld.AllPlayers1[i]; ch.SaveCharToDisk(); }
                catch (Exception ex) { LogError("CrashHandler: Could not save player to disk on game exit", ex, LogType.Always); }
                try { TopTenData.Save(1); }
                catch (Exception ex) { LogError("CrashHandler: Error saving topten", ex, LogType.Always); }
                try { RatingData.Save(1); }
                catch (Exception ex) { LogError("CrashHandler: Error saving rating data", ex, LogType.Always); }
                try { PlayerbaseData.Save(1); }
                catch (Exception ex) { LogError("CrashHandler: Error saving playerbase data", ex, LogType.Always); }
            }
        }

        /// <summary>
        /// This actually performs the "hits" or casts the spell/etc
        /// A return value of false means that the character is no long attacking the
        /// targetOfAction and should be removed from the fighting list
        /// </summary>
        /// <param name="chAttacker"></param>
        /// <param name="chTarget"></param>
        /// <returns></returns>
        public static bool PerformCombatRound(CharacterData chAttacker, CharacterData chTarget)
        {
            int nDamage = 50;

            StringCodeCollection stringformatter = new StringCodeCollection(ShowFlags.None);
            // For now.. keep it simple
            stringformatter.DisplayCodedStringTo(
              DisplaysTo.chInitiated | DisplaysTo.BystandersInCharRoom | DisplaysTo.Target,
              "|CName smack(s) |TName for " + nDamage.ToString() + " damage...",
              chAttacker, chTarget, null, null, "someone", "someone");

            CharPosition posNew = TakeDirectDamage(chTarget, nDamage);

            if (posNew == CharPosition.dead)
            {
                chTarget.DoCharacterDeath();
                return false;
            }
            return true;
        }


        public static CharPosition TakeDirectDamage(CharacterData chr, int nDamageAmount)
        {
            CharPosition oldPosition = chr.position;
            CharPosition newPosition = chr.position;

            chr.HPCurrent -= nDamageAmount;

            if (chr.HPCurrent <= 5)
            {
                if (chr.HPCurrent < 0)
                    newPosition = CharPosition.dead;
                else
                {
                    if (chr.HPCurrent <= 2)
                    {
                        newPosition = CharPosition.dying;
                    }
                    else
                    {
                        newPosition = CharPosition.incapacitated;
                    }
                }
            }

            if (oldPosition != newPosition)
            {
#if NO_SILVERLIGHT
                chr.send_to_char("You are " + Enum.Format(typeof(CharPosition), newPosition, "G") + "...");
#else
                chr.send_to_char("You are " + ((CharPosition)newPosition).ToString() + "...");
#endif
            }

            return newPosition;
        }


        public static void DoSocial(CharacterData ch, ISocialData social, string szUserArguments)
        {
            string szTarget = "";
            szUserArguments = szUserArguments.Trim();
            bool fNoTargetSpecified = false;
            int nLoc = szUserArguments.IndexOf(' ');
            if (nLoc <= 0)
            {
                // No targetOfAction specified
                fNoTargetSpecified = true;
            }
            else
            {
                szTarget = szUserArguments.Substring(nLoc + 1);
            }

            StringCodeCollection interpretter = new StringCodeCollection();
            if (fNoTargetSpecified)
            {
                if (!StaticHelpers.Empty(social.Char_no_arg, "none"))
                {
                    interpretter.DisplayCodedStringTo(DisplaysTo.chInitiated,
                      "{W}" + social.Char_no_arg, ch, ch, null, null, "someone", "someone");
                }
                if (!StaticHelpers.Empty(social.Others_no_arg, "none"))
                {
                    interpretter.DisplayCodedStringTo(DisplaysTo.BystandersInCharRoom,
                      social.Others_no_arg, ch, ch, null, null, "someone", "someone");
                }
            }
            else
            {
                CharacterData chrTo = ch.FindCharacterInRoom(szTarget, true);
                if (szTarget.Equals("self", StringComparison.OrdinalIgnoreCase) == true ||
                  chrTo == ch)
                {
                    if (!StaticHelpers.Empty(social.Char_auto, "none"))
                    {
                        interpretter.DisplayCodedStringTo(DisplaysTo.chInitiated,
                          "{W}" + social.Char_auto, ch, null, null, null, "someone", "someone");
                    }
                    if (!StaticHelpers.Empty(social.Others_auto, "none"))
                    {
                        interpretter.DisplayCodedStringTo(DisplaysTo.BystandersInCharRoom,
                          social.Others_auto, ch, ch, null, null, "someone", "someone");
                    }
                }
                else
                {
                    if (chrTo == null)
                    {
                        if (!StaticHelpers.Empty(social.Char_not_found, "none"))
                        {
                            interpretter.DisplayCodedStringTo(DisplaysTo.chInitiated,
                              "{W}" + social.Char_not_found, ch, ch, null, null, "someone", "someone");
                        }

                    }
                    else
                    {	// a specified targetOfAction was found in the room
                        if (!StaticHelpers.Empty(social.Vict_found, "none"))
                        {
                            interpretter.DisplayCodedStringTo(DisplaysTo.chInitiated,
                              "{W}" + social.Vict_found, chrTo, ch, null, null, "someone", "someone");
                        }

                        if (!StaticHelpers.Empty(social.Others_found, "none"))
                        {
                            interpretter.DisplayCodedStringTo(DisplaysTo.chInitiated | DisplaysTo.BystandersInCharRoom,
                              social.Others_found, ch, chrTo, null, null, "someone", "someone");
                        }
                    }
                }
            }
        }

        public static ISocialData FindSocial(CharacterData chr, string szSocial, bool fExactMatch)
        {
            if (StaticHelpers.Empty(szSocial, true)) return null;
            for (int i = 0; i < WorldTemplates.AllSocials.Count; i++)
            {
                SocialData social = (SocialData)WorldTemplates.AllSocials[i];
                if (social.Socialname.Equals(szSocial, StringComparison.OrdinalIgnoreCase) == true)
                {
                    social.nUses++;
                    return social;
                }
            }
            if (fExactMatch == true) return null;
            for (int i = 0; i < EmlenMud.WorldTemplates.AllSocials.Count; i++)
            {
                SocialData social = (SocialData)EmlenMud.WorldTemplates.AllSocials[i];
                if (social.Socialname.StartsWith(szSocial, StringComparison.OrdinalIgnoreCase) == true)
                {
                    social.nUses++;
                    return social;
                }
            }
            return null;
        }

        public static string DisplayAllSocials(CharacterData chr)
        {
            StringBuilder sb = new StringBuilder(12000);
            bool fImmort = chr.Immortal;
            WorldTemplates.AllSocials.Sort();
            //HtmlTable tbl = new System.Web.UI.HtmlControls.HtmlTable();
            //tbl.Width = "99%";
            //tbl.CellPadding = 2;
            //tbl.CellSpacing = 0;
            //tbl.Border = 0;
            //tbl.Style.Add(HtmlTextWriterStyle.BorderColor, "#CCFF99");
            //tbl.Style.Add(HtmlTextWriterStyle.BorderStyle, "solid");
            //tbl.Style.Add(HtmlTextWriterStyle.BorderWidth, "2px");
            //HtmlTableRow HRow = new HtmlTableRow();
            //HRow.VAlign = "top";
            //HRow.Align = "center";
            //HRow.Style.Add(HtmlTextWriterStyle.FontWeight, "bold");
            //HRow.Style.Add(HtmlTextWriterStyle.Color, "#33FF33");
            //HtmlTableCell tc = new HtmlTableCell();
            //tc.ColSpan = 12;
            //tc.InnerHtml = "<strong style='font-size: larger;'>List of Socials</strong>";
            //HRow.Cells.Add(tc);
            //tbl.Rows.Add(HRow);
            //HtmlTableRow tr = new HtmlTableRow();
            //tr.Align = "left";
            //tr.Style.Add(HtmlTextWriterStyle.Color, "#FFFFFF");
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Social";
            //tr.Cells.Add(tc);
            //tc = new HtmlTableCell();
            //tc.InnerHtml = "Uses";
            //tr.Cells.Add(tc);
            //tbl.Rows.Add(tr);
            //tr = null;

            //int nCount = 0;
            //for (int i = 0; i < chr.WorldTemplates.AllSocials.Count; i++)
            //{
            //    if ((nCount % 6) == 0)
            //    {
            //        if (tr != null) tbl.Rows.Add(tr);
            //        tr = new HtmlTableRow();
            //        tr.Align = "left";
            //        tr.VAlign = "top";
            //    }
            //    SocialData social = (SocialData)chr.WorldTemplates.AllSocials[i];
            //    if (StaticHelpers.Empty(social.Socialname)) continue;
            //    tc = new HtmlTableCell();
            //    tc.InnerHtml = " " + social.Socialname + " ";
            //    tr.Cells.Add(tc);
            //    tc = new HtmlTableCell();
            //    tc.InnerHtml = " " + social.nUses.ToString() + " ";
            //    tr.Cells.Add(tc);
            //    nCount++;
            //}

            //if (tr != null && tr.Cells.Count > 0) tbl.Rows.Add(tr);
            //StringWriter swriter = new StringWriter(sb);
            //System.Web.UI.HtmlTextWriter tw = new System.Web.UI.HtmlTextWriter(swriter);
            //tbl.RenderControl(tw);
            //tw.Flush();
            //sb = swriter.GetStringBuilder();
            //sb.Insert(0, "<center>");
            //sb.Append("</center>");
            //sb.Replace("\n", "");
            //sb.Replace("\r", "");
            return sb.ToString();
        }


        public static bool AddCommand(ICommand cmd)
        {
            //if (cmd.EmlenMud == null) cmd.AssignEmlenMud(this);
            if (WorldTemplates.htCommands.ContainsKey(cmd.Commandstring.ToUpper()) == false)
            {
                WorldTemplates.htCommands.Add(cmd.Commandstring.ToUpper(), (ICommand)cmd);
                WorldTemplates.rgCommands.Add((ICommand)cmd);

                List<ICommand> rg = null;
                if (WorldTemplates.htCommandListsByFirstTwoLetters.ContainsKey(StaticHelpers.FirstTwoLettersHash(cmd.Commandstring.ToUpper())) == false)
                {
                    rg = new List<ICommand>(8);
                    WorldTemplates.htCommandListsByFirstTwoLetters.Add(StaticHelpers.FirstTwoLettersHash(cmd.Commandstring.ToUpper()), rg);
                }
                else
                {
                    rg = WorldTemplates.htCommandListsByFirstTwoLetters[StaticHelpers.FirstTwoLettersHash(cmd.Commandstring.ToUpper())];
                }
                rg.Add((ICommand)cmd);
                return true;
            }
            return false;
        }


        public static ICommand FindCommand(string sz, bool fExactMatch)
        {
            if (sz == null) return null;
            string szCmd;
            int nSpace = sz.IndexOf(" ", 0, StringComparison.OrdinalIgnoreCase);
            if (nSpace >= 1)
            {
                szCmd = sz.Substring(0, nSpace).ToUpper();
            }
            else
            {
                szCmd = sz.ToUpper();
            }
            if (WorldTemplates.htCommands.ContainsKey(szCmd) == true)
            {
                return (Command)WorldTemplates.htCommands[szCmd];
            }
            if (fExactMatch == true) return null;
            List<ICommand> rg = null;
            if (WorldTemplates.htCommandListsByFirstTwoLetters.ContainsKey(StaticHelpers.FirstTwoLettersHash(szCmd)) == true)
            {
                rg = WorldTemplates.htCommandListsByFirstTwoLetters[StaticHelpers.FirstTwoLettersHash(szCmd)];
            }
            if (rg != null)
            {
                for (int n = 0; n < rg.Count; n++)
                {
                    Command cmd = (Command)rg[n];
                    if (cmd.Commandstring.ToUpper().StartsWith(szCmd, StringComparison.OrdinalIgnoreCase) == true)
                    {
                        return cmd;
                    }
                }
            }
            return null;
        }

        public static void RecursiveRegisterObjects(CharacterData carrier, RoomData room, CharacterData storedby, List<ObjectData> rg, ObjectData containerObject)
        {
            for (int n = 0; n < rg.Count; n++)
            {
                ObjectData obj = (ObjectData)rg[n];
                if ((carrier != null && obj.Carried_by == null) ||
                    (room != null && obj.In_roomInternal == null) ||
                    (storedby != null && obj.Stored_by == null))
                {
                    //obj.AssignEmlenMud(EmlenMud);
                    obj.Carried_by = carrier;
                    obj.Stored_by = storedby;
                    obj.in_room = room;
                    obj.In_obj = containerObject;
                    if (obj.More != null)
                    {
                        //foreach (MudThing mt in obj.More)
                        //{
                        //    mt.AssignEmlenMud(EmlenMud);
                        //}
                    }
                    if (obj.Contains != null)
                    {
                        RecursiveRegisterObjects(carrier, room, storedby, obj.Contains, obj);
                    }
                    List<ObjectData> rgObjs = null;
                    if (DynamicWorld.ObjectsByProtoVnum1.ContainsKey(obj.VnumObjProto) == false)
                    {
                        rgObjs = new List<ObjectData>(32);
                    }
                    else
                    {
                        rgObjs = EmlenMud.DynamicWorld.ObjectsByProtoVnum1[obj.VnumObjProto];
                    }
                    rgObjs.Add(obj);
                    DynamicWorld.AllObjects1.Add(obj);
                }
            }
        }


        /// <summary>
        /// Loads a character/player from disk
        /// </summary>
        /// <param name="szName">the exact name of the player/character</param>
        /// <returns></returns>
        public CharacterData LoadCharFromDisk(string szName)
        {
#if NO_SILVERLIGHT
            string szstring = szName;
            string szFileName = HostPathnameToMudDirectory + "\\" + MiscConstants.PLAYER_DIR + "\\" + szstring;
            Object o = SerializationHelper.SerializeObjectIn(szFileName);
            if (o == null) return null;
            if (o is CharacterData)
            {
                CharacterData chr = (CharacterData)o;
                //chr.AssignEmlenMud(this);
                if (chr.position == CharPosition.fighting) chr.position = CharPosition.standing;
                return chr;
            }
#endif
            return null;
        }

        /// <summary>
        /// Checks if a character/player exists on disk
        /// </summary>
        /// <param name="szName">the exact name of the player or character</param>
        /// <returns></returns>
        public bool CharExistsOnDisk(string szName)
        {
            string szstring = szName;
            string szFileName = HostPathnameToMudDirectory + "\\" + MiscConstants.PLAYER_DIR + "\\" + szstring + ".ace";
            return (File.Exists(szFileName) == true);
        }


        public static CharacterData CreateNewCharacterData()
        {
            CharacterData chr = new CharacterData(true);
            return chr;
        }


        public static CharacterData CreateInstanceOfMobPrototype(MobPrototype mp)
        {
            // TODO: NYI - Special functions
            CharacterData mob = new CharacterData();
            mob.mobPrototype = mp;
            mob.position = CharPosition.standing;
            
            if (mp.Timer > 0)
                mob.MobSelfDestructsAt = DateTime.Now.AddMinutes(mp.Timer);
            
            mob.CurrentActionsAndBehavior = mp.PrototypeBehaviors;
            mob.height = mp.Height;
            mob.CurrentlyAffectedBy = mp.PrototypeEffects;

            if (mp.Money >= 99)
            {
                mob.Copper = Rand.RandIntBetween(mp.Money / 4, mp.Money - 1) + 1;
                mob.RecalcMoney();
            }
            else
            {
                mob.Copper = mp.Money;
                mob.Gold = 0;
            }
            if (mp.Armcls == 101)
            {
                mob.NaturalArmor = 99 - (Rand.RandIntBetween(mob.Level / 3, mob.Level)) - mob.Level;
                if (mob.NaturalArmor <= -30)
                    mob.NaturalArmor /= 2;
            }
            else
            {
                mob.NaturalArmor = mp.Armcls;
            }

            mob.HPMax = mob.CalculateInitialHP();
            mob.MPMax = mob.CalculateInitialMP();
            mob.GainLevel(mob.mobPrototype.Level - 1);

            // It's important to calculate the mob's damageRoll before applying
            // the before modifying their max HPCurrent points using the hp multiplier option!
            // Otherwise damageRoll goes sky high or drops like a rock
            // if this mob has any kind of HPCurrent point bonus or penalty

            mob.DamageRoll = 4 + (mob.HPMax / (Rand.RandIntBetween(9, 12)));

            // Okay, now apply the HPCurrent point modifier
            mob.HPMax = (mob.HPMax * 10 * (mp.Hpmult > 1000 ? (mp.Hpmult % 1000) : mp.Hpmult)) / 100;
            if (mob.HPMax <= 1) { mob.HPMax = 3; }

            mob.RestoreHP();
            mob.RestoreMP();
            mob.SetMobExperience();
            mob.Name = new NameAndDescription()
            {
                Name = mp.Short_descr,
                Description = mp.Long_descr,
                _keywords = mp.mobprototypenameI,
                ShortDescription = mp.Short_descr
            };
            mob.Hitroll = Math.Max(7, EmlenMud.Fuzzy(mob.Level, 20) / 2);
            EmlenMud.SetInRoom(mob, null);
            return mob;
        }

        /// <summary>
        /// Exactly like <see cref="ShortName">ShortName</see>, but with the
        /// looker and targetOfAction reversed.  This returns the short name
        /// of chrTarget as seen by the current character.  This function
        /// does NOT check if one character can see the other.  You should
        /// call CanSee(CharacterData) before use.
        /// </summary>
        /// <param name="chrTarget"></param>
        /// <returns></returns>
        public string NameOf(CharacterData chrTarget, CharacterData chrLooker)
        {
            return ShortName(chrLooker, chrTarget);
        }

        /// <summary>
        /// How this character appears (name-wise) to the looker.
        /// This function does NOT check if one character
        /// can see the other, and therefore CanSee(CharacterData) must
        /// be called in most cases before using ShortName
        /// </summary>
        /// <param name="chrLooker">The character that is looking at the
        /// current character</param>
        /// <returns></returns>
        public static string ShortName(CharacterData chrLooker, CharacterData chrTarget)
        {
            // Add good/evil, alien/human code here
            if (string.IsNullOrEmpty(chrTarget.ShortName))
            {
                if (chrTarget.IsMob)
                {
                    MobPrototype mp = (MobPrototype)chrTarget.mobPrototype;
                    if (mp != null)
                    {
                        if (mp.Short_descr != null)
                        {
                            return mp.Short_descr;
                        }
                        else
                        {
                            return mp.Mobprototypename;
                        }
                    }
                }
                else if (chrTarget.IsPlayer)
                {
                    if (!string.IsNullOrEmpty(chrTarget.ShortName)) return chrTarget.ShortName;
                    else if (!string.IsNullOrEmpty(chrTarget.pcdata.Short_descr)) return chrTarget.pcdata.Short_descr;
                }

                if (chrTarget.Description != null) return chrTarget.Description;
                else return "";
            }
            else
            {
                return chrTarget.ShortName;
            }
        }

        public static bool SetFollowing(IFightData fgt, CharacterData ch, CharacterData chToFollow)
        {
            StringBuilder sb = new StringBuilder(1024);
            bool fStoppedFollowing = false;

            if (fgt.FollowingCharacter != null || fgt.FollowingCharacter == ch)
            {
                if (chToFollow == fgt.FollowingCharacter)
                {
                    ch.send_to_char("You are already following " + EmlenMud.ShortName(ch, chToFollow) + "!");
                    return true;
                }

                // stop following the previous character
                fgt.FollowingCharacter.send_to_char(EmlenMud.ShortName(fgt.FollowingCharacter, ch) + " stops following you.\n\r");
                sb.Append("You stop following ");
                sb.Append(EmlenMud.ShortName(ch, fgt.FollowingCharacter));
                fStoppedFollowing = true;
                fgt.FollowingCharacter = null;
            }

            if (chToFollow != null)
            {
                // begin following the specified character
                // TODO: HEREHERE: Check if the character is allowed to follow
                if (fStoppedFollowing)
                {
                    sb.Append(" and begin following ");
                    sb.Append(EmlenMud.ShortName(ch, chToFollow));
                }
                else
                {
                    sb.Append("You begin following ");
                    sb.Append(EmlenMud.ShortName(ch, chToFollow));
                }

                chToFollow.send_to_char(EmlenMud.ShortName(chToFollow, ch) + " begins following you.\n\r");
                fgt.FollowingCharacter = chToFollow;
            }
            else
            {
                if (fgt.FollowingCharacter != null)
                {
                    fgt.FollowingCharacter.send_to_char(EmlenMud.ShortName(fgt.FollowingCharacter, ch) + " stops following you.\n\r");
                }

                fgt.FollowingCharacter = null;
            }

            sb.Append(".");
            ch.send_to_char(sb.ToString());
            return true;
        }

        /// <summary>
        /// Handles track-making (checks if the character makes trcks,
        /// and then updates or adds trcks info)
        /// </summary>
        /// <param name="performingCharacter">Character</param>
        /// <param name="dir">Direction from which they entered or in which they left</param>
        /// <param name="enterOrLeave">whether they left or entered from <paramref>dir</paramref></param>
        /// <returns>Whether or not any track was made</returns>
        public static bool HandleMakingTracks(RoomData room, CharacterData ch, GeneralDirection dir, EnterOrLeave enterOrLeave)
        {
            // TODO
            //if (ch.LeavesTracks(room))
            //{
            //    DynamicRoomDetails dyn = (DynamicRoomDetails)room.MoreRoomInfo;
            //    if (dyn.Tracks == null) { dyn.Tracks = new ThreadSafeLookup<INamedMudThing, ITrackData>(4); }
            //    TrackData track;
            //    if (dyn.Tracks.ContainsKey(ch) == false)
            //    {
            //        track = new TrackData(this);
            //        track.Ch = ch;
            //        track[enterOrLeave] = dir;
            //        dyn.Tracks.Add(ch, (ITrackData)track);
            //    }
            //    else
            //    {
            //        track = (TrackData)(dyn.Tracks[ch]);
            //        track.Ch = ch;
            //        track[enterOrLeave] = dir;
            //    }

            //    return true;
            //}
            return false;
        }

        /// <summary>
        /// Adjusts the lighting in the currentRoom based on lit objects
        /// the character is currently wearing
        /// </summary>
        /// <param name="fEnteringRoom">true if entering the currentRoom, false if leaving</param>
        public static void AutoAdjustRoomLighting(RoomData room, CharacterData ch, bool fEnteringRoom)
        {
            foreach (ObjectData obj in ch.CarryingObjects)
            {
                if (obj.IsBeingWorn)
                {
                    List<ItemLight> rgLights = obj.FindLights();
                    if (rgLights != null)
                    {
                        foreach (ItemLight lt in rgLights)
                        {
                            if (fEnteringRoom)
                            {
                                if (lt.IsLit()) room.MoreRoomInfo.LightingAmount++;
                            }
                            else
                            {
                                if (lt.IsLit() && room.MoreRoomInfo.LightingAmount > 0) room.MoreRoomInfo.LightingAmount--;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// You MUST make sure the character has been removed from a room
        /// (i.e. they are NOT in another room), or this call will return false
        /// </summary>
        /// <param name="performingCharacter">The character who is currently NOT in a room</param>
        /// <returns>false if (1) you messed up and passed in a character that
        /// was in a room, or (2) if the character is being added to the same
        /// room it is already in.</returns>
        public static bool AddCharacterToRoom(CharacterData ch, RoomData room)
        {
            if (ch.vnumInRoom != 0) return false;
            if (room.characters.Contains(ch) == true) return false;

            AutoAdjustRoomLighting((RoomData)room, ch, true);
            room.characters.Add(ch);
            DynamicRoomDetails dyn = (DynamicRoomDetails)room.MoreRoomInfo;
            if (ch.IsPlayer)
            {
                dyn.NumberOfPlayersInRoom++;
                if (room.area != null) room.area.PlayersInArea++;
                if (dyn.NumberOfPlayersInRoom == 1)
                {
                    for (int i = 0; i < dyn.CharactersInRoom.Count; i++)
                    {
                        CharacterData chrMob = dyn.CharactersInRoom[i];
                        if (chrMob.IsAggressive)
                        {
                            DynamicWorld.AggressiveMobs.Add(ch);
                        }
                    }
                }
            }
            if (ch.IsMob && dyn.NumberOfPlayersInRoom > 0)
            {
                if (ch.IsAggressive)
                {
                    if (!DynamicWorld.AggressiveMobs.Contains(ch))
                        DynamicWorld.AggressiveMobs.Add(ch);
                }
            }

            return true;
        }

        /// <summary>
        /// This does not actually change the character's room, but it
        /// registers with the room that the character is no longer there.
        /// </summary>
        /// <param name="performingCharacter"></param>
        /// <returns></returns>
        public static bool RemoveCharacterFromRoom(CharacterData ch, RoomData room)
        {
            if (!room.HasCharacters) { return false; }
            if (room.characters.Contains(ch) == false) { return false; }

            AutoAdjustRoomLighting((RoomData)room, ch, false);
            room.characters.Remove(ch);
            DynamicRoomDetails dyn = (DynamicRoomDetails)room.MoreRoomInfo;
            if (ch.IsPlayer)
            {
                dyn.NumberOfPlayersInRoom--;
                if (room.area != null) room.area.PlayersInArea--;
                if (dyn.NumberOfPlayersInRoom == 0)
                {
                    for (int i = 0; i < dyn.CharactersInRoom.Count; i++)
                    {
                        CharacterData chrMob = dyn.CharactersInRoom[i];
                        if (chrMob.IsAggressive)
                        {
                            DynamicWorld.AggressiveMobs.Remove(chrMob);
                        }
                    }
                    // Just charmed a mob in combat?
                    // Really, I have no clue what the heck is going on here...
                    // I am tempted just to rip it out....
                    //if (chs.IsMob && chs.IsCurrentlyAffectedBy(EffectType.CHARM) &&
                    //  chs.fightInfoInternal != null)
                    //{
                    //  if (chs.fightInfoInternal.chMaster == this)
                    //  {
                    //    if (pcdata.pets.Contains(chs) == false)
                    //    {
                    //      pcdata.pets.Add(chs);
                    //      pcdata.pet_temp.Add(chs.mobPrototype.vnumClan);
                    //      pcdata.pet_hps.Add(chs.HPCurrent);
                    //      pcdata.pet_move.Add(chs.MPCurrent);
                    //    }
                    //  }
                    //}
                }
            }
            if (ch.IsAggressive && dyn.NumberOfPlayersInRoom == 0)
            {
                DynamicWorld.AggressiveMobs.Remove(ch);
            }

            if (ch.IsFighting)
            {
                ch.FightInfo = null;
            }

            return true;
        }


        public static void DoReset(RoomData room)
        {
            for (int iExit = 0; iExit < (int)GeneralDirection.Max; iExit++)
            {
                ExitData ex = (ExitData)room.Exits[iExit];
                if (ex != null)
                {
                    //if (ex.EmlenMud == null) ex.AssignEmlenMud(this);
                    ex.ResetExit(iExit);
                }
            }
            if (room.MoreRoomInfo == null) return;

            CharacterData LastMob = null;
            foreach (ResetData pReset in room.Resets)
            {
                if (Rand.RandIntBetween(0, 100) > pReset.Percent)
                    continue;

                if (pReset.Command == 'M')
                {
                    MobPrototype mproto = null;
                    if (WorldTemplates.AllMobPrototypes.ContainsKey(pReset.Rs_vnum) == true)
                    {
                        mproto = WorldTemplates.AllMobPrototypes[pReset.Rs_vnum];
                    }
                    if (mproto == null)
                    {
                        LastMob = null;
                        continue;
                    }
                    Object o = DynamicWorld.WorldStats.Mobinstancecount[mproto.Vnum];
                    if (o != null)
                    {
                        int nMobsOfThisTypeInWorld = (int)o;
                        // Sorry, already too many mobs of this type, don't create another
                        if (nMobsOfThisTypeInWorld >= mproto.MaxInWorld)
                        {
                            LastMob = null;
                            continue;
                        }
                    }
                    if (LastMob != null)
                    {
                        if (room.IsDark()) LastMob.CurrentlyAffectedBy |= (long)EffectType.INFRARED;
#if NO_SILVERLIGHT
                        LastMob.AddToCharListAndPlaceInGame(null, room, true);
#endif
                    }

                    LastMob = (CharacterData)CreateInstanceOfMobPrototype(mproto);
                }
            }

            #region "HEREHERE: Working on RepopMessage"
            // HEREHERE
            // int olevel = 2;    



            /* Mob was born, check for triggers on mobbie! */
            //   checkagain:
            //     {
            //       SINGLE_TRIGGER *tr;
            //       SCRIPT_INFO *s;
            //       for (tr = trigger_list[TCREATED]; tr != NULL; tr = tr.next)
            //         {
            //      if (pMob.mobPrototype.vnumClan == tr.attached_to_mob)
            //        {
            //          if (tr.running_info && !tr.interrupted)
            //            continue;	/* Already running, interrupted, but script says not to allow interruptions. */
            //          if (tr.running_info && tr.interrupted != 2)
            //            {
            //         end_script (tr.running_info);
            //         goto checkagain;
            //            }
            //          /* ----------------- */
            //          /* Start the script! */
            //          /* ----------------- */
            //          tr.running_info = new SCRIPT_INFO;// (sizeof (*tr.running_info));
            //          s = tr.running_info;
            //          bzero (s, sizeof (*s));
            //          s.current = pMob;
            //          s.mob = pMob;
            //          strcpy (s.code_seg, tr.code_label);
            //          s.current_line = 0;
            //          s.called_by = tr;
            //          s.next = info_list;
            //          info_list = s;
            //          execute_code (s);
            //          /* ----------------- */
            //        }
            //         }
            //     }
            ///* End trigger check! */


            //     if (IS_AFFECTED (pMob, AFF_SLEEP))
            //       {
            //         do_sleep (pMob, "");
            //       }
            //     if (IS_SET (pMob.mobPrototype.act3, RIDE))
            //       {
            //         if (LastMob != NULL && RIDING (LastMob) == NULL)
            //      {
            //        do_mount (pMob, RNAME (LastMob));
            //      }
            //       }
            //     if (IS_SET (pMob.mobPrototype.act3, FOLLOW))
            //       {
            //         if (LastMob != NULL)
            //      {
            //        add_follower (pMob, LastMob);
            //      }
            //       }
            //     LastObj = NULL;
            //     LastObjPrev = NULL;
            //     LastMob = pMob;
            //     olevel = LEVEL (pMob);
            //     handle_points(pMobIndex,pMob);
            //     if (pMobIndex.vnumClan < 10000 && g_mobpop[pMobIndex.vnumClan])
            //       {
            //         int iet;
            //         bool fndit;
            //         dum ();
            //tti:
            //         fndit = FALSE;
            //         for (; ie < MAX_RANDOMPOP; ie++)
            //      {
            //        if (g_obj_pop[ie] == 0)
            //          continue;
            //        for (iet = 0; iet < 10; iet++)
            //          {
            //            if (g_moblist[ie][iet] == pMobIndex.vnumClan)
            //         {
            //           fndit = TRUE;
            //           goto ffjt;
            //         }
            //          }
            //      }
            //       ffjt:
            //         if (fndit)
            //      {
            //        if (number_range (1, 254) < g_percent[ie])
            //          {
            //            if ((pObjIndex = get_obj_index (g_obj_pop[ie])) == NULL)
            //         {
            //           continue;
            //         }
            //            if (pObjIndex.vnumClan < MAX_LIMITED && pObjIndex.how_many > 0 &&
            //           pObjIndex.how_many <= limited.limited_array[pObjIndex.vnumClan])
            //         continue;
            //            pObj = create_object (pObjIndex, 7);
            //            obj_to_char (pObj, pMob);
            //            wear_obj (pMob, pObj, FALSE, 0);
            //         ie++;
            //         goto tti;
            //          }
            //      }
            //       }


            //            }

            //         }
            //  break;
            //case 'O':
            //  pObj = NULL;
            //  if ((pObjIndex = get_obj_index (pReset.rs_vnum)) == NULL)
            //    {
            //      bug ("Reset_room: 'O': bad vnumClan %d.", pReset.rs_vnum);
            //      bug ("Reset in currentRoom : %d.", pRoom.vnumClan);
            //      continue;
            //    }
            //  if (pObjIndex.vnumClan < MAX_LIMITED && pObjIndex.how_many > 0 &&
            //      pObjIndex.how_many <= limited.limited_array[pObjIndex.vnumClan])
            //    continue;
            //  if (pReset.loc == RESET_LOC_INROOM)
            //    {
            //      SINGLE_OBJECT *obj2;
            //      int count_in_room;
            //      count_in_room = 0;
            //      if (pRoom.MoreRoomInfo)
            //   for (obj2 = pRoom.MoreRoomInfo.contents; obj2 != NULL; obj2 = obj2.next_content)
            //     {
            //       if (obj2.mobPrototype.vnumClan == /*pObj.mobPrototype.vnumClan */ pObjIndex.vnumClan)
            //         count_in_room++;
            //     }
            //      if (pObjIndex.max_in_room <= count_in_room)
            //   continue;
            //      pObj = create_object (pObjIndex, number_fuzzy (olevel));
            //      obj_to_room (pObj, pRoom);
            //      if ( /*LastObj == NULL || */ pObj.mobPrototype.item_type == ITEM_CONTAINER)
            //   {
            //     LastObjPrev = LastObj;
            //     LastObj = pObj;
            //   }
            //      continue;
            //    }
            //  if (pReset.loc == RESET_LOC_INOBJ && LastObj != NULL)
            //    {
            //      pObj = create_object (pObjIndex, number_fuzzy (olevel));
            //      obj_to_obj (pObj, LastObj);
            //      continue;
            //    }
            //  if (pReset.loc == RESET_LOC_ONOBJ && LastObj != NULL)
            //    {
            //      pObj = create_object (pObjIndex, number_fuzzy (olevel));
            //      obj_to_obj (pObj, LastObj);
            //      continue;
            //    }
            //  if (LastMob != NULL)
            //    {
            //      pObj = create_object (pObjIndex, number_fuzzy (olevel));
            //      obj_to_char (pObj, LastMob);
            //      if ( /*LastObj == NULL || */ pObj.mobPrototype.item_type == ITEM_CONTAINER)
            //   {
            //     LastObjPrev = LastObj;
            //     LastObj = pObj;
            //   }
            //      /* For Shopkeepers */
            //      if (LastMob.mobPrototype.pShop != NULL
            //     && pObj.wear_loc == WEAR_NONE)
            //   {
            //     /* pObj.wear_loc = URANGE( WEAR_NONE, pReset.loc, MAX_WEAR ); */
            //     pObj.wear_loc = -1;
            //     SET_BIT (pObj.extra_flags, ITEM_INVENTORY);
            //     if (pReset.loc > 1)
            //       {
            //         int counter;
            //         for (counter = 1; counter < pReset.loc; counter++)
            //      {
            //        pObj = NULL;
            //        pObj = create_object (pObjIndex, 1);
            //        obj_to_char (pObj, LastMob);
            //        pObj.wear_loc = WEAR_NONE;
            //        SET_BIT (pObj.extra_flags, ITEM_INVENTORY);
            //      }
            //       }
            //     continue;
            //   }
            //      if (pReset.loc != 99)
            //   wear_obj (LastMob, pObj, FALSE, 0);
            //    }
            //  break;
            //}

            //   }
            #endregion
            if (LastMob != null)
            {
                if (room.IsDark()) LastMob.CurrentlyAffectedBy |= (long)EffectType.INFRARED;
#if NO_SILVERLIGHT
                LastMob.AddToCharListAndPlaceInGame(null, room, true);
#endif
            }
        }

        public static RoomData FindValidStartingRoom(CharacterData chr)
        {
#if NO_SILVERLIGHT
            RoomData room = null;
            IDescriptorData dd = chr.descriptor;
            room = EmlenMud.WorldTemplates.GetRoom(450);
            if (room == null)
            {
                room = EmlenMud.WorldTemplates.GetRoom(1001);
                if (room == null)
                {
                    room = EmlenMud.WorldTemplates.GetRoom(100);

                    if (room == null)
                    {
                        room = EmlenMud.WorldTemplates.GetRoom(1);
                        if (room == null)
                        {
                            // create a frickin' currentRoom for the character to be put in to :)
                            AreaData area = (AreaData)EmlenMud.WorldTemplates.CreateNewArea(999, "First Area", "first_area.are", 1);
                            if (area.RoomsInArea.Count > 0)
                            {
                                room = (RoomData)area.RoomsInArea[0];
                            }
                        }
                    }
                }
            }
            return room;
#else
            return null;
#endif
        }

        public static void HandleWalkthroughCreation(CharacterData ch1, PlayerData ch2, RoomData room)
        {
            PlayerData ch = (PlayerData)ch2;
            RaceData race = (RaceData)ch.GetRaceData();
            if (race != null)
            {
                if (room.VnumRoom > 410 && room.VnumRoom < 500)
                {
                    if (room.VnumRoom == 450)
                    {
                        ch.Nat_abilities = 0;
                        ch1.CurrentlyAffectedBy = 0;
                        ch.PermanentStats1[StatTypes.Strength] = Rand.RandIntBetween(13, 15);
                        ch.PermanentStats1[StatTypes.Intelligence] = Rand.RandIntBetween(13, 14);
                        ch.PermanentStats1[StatTypes.Constitution] = Rand.RandIntBetween(13, 15);
                        ch.PermanentStats1[StatTypes.Dexterity] = Rand.RandIntBetween(12, 15);
                        ch.PermanentStats1[StatTypes.Wisdom] = Rand.RandIntBetween(12, 14);
                        ch.PermanentStats1[StatTypes.Strength] += race.Bonus[0];
                        ch.PermanentStats1[StatTypes.Intelligence] += race.Bonus[1];
                        ch.PermanentStats1[StatTypes.Wisdom] += race.Bonus[2];
                        ch.PermanentStats1[StatTypes.Dexterity] += race.Bonus[3];
                        ch.PermanentStats1[StatTypes.Constitution] += race.Bonus[4];
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 452)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 460)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(2, 4);
                        ch.PermanentStats1[StatTypes.Wisdom] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(2, 4);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(2, 4);
                        // TODO: gain_exp (chr, 700);
                        ch1.MPMax += 1;
                        ch1.MPCurrent += 1;
                        ch1.HPMax += 3;
                        ch1.HPCurrent += 3;
                        ch.learned.AddOrSet((int)GeneralSN.SlashingWeapons, 10);
                        ch.learned.AddOrSet((int)GeneralSN.Parry, 7);
                        ch.learned.AddOrSet((int)GeneralSN.PiercingWeapons, 6);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 464)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 2);
                        ch1.MPMax += 6;
                        ch1.MPCurrent += 6;
                        // TODO: gain_exp (chr, 200);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 4);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 465)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += 2;
                        ch.PermanentStats1[StatTypes.Constitution] += 2;
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 461)
                    {
                        ch1.MPMax += 4;
                        ch1.MPCurrent += 4;
                        // TODO: gain_exp (chr, 600);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Wisdom] += 2;
                        ch.PermanentStats1[StatTypes.Intelligence] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(3, 4);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(2, 4);
                        ch.learned[(int)GeneralSN.Sneaking] = 8;
                        ch.learned[(int)GeneralSN.PiercingWeapons] = 9;
                        ch.learned[(int)GeneralSN.SlashingWeapons] = 6;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 453)
                    {

                        ch.PermanentStats1[StatTypes.Intelligence] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Wisdom] += 2;
                        // TODO: gain_exp (chr, 350);
                        ch.learned[(int)GeneralSN.Searching] = 5;
                        ch.learned[(int)GeneralSN.EnhancedDamage] = 5;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 458)
                    {
                        // if (Rand.RandIntBetween(1,3)==2) nat_abilities |= EFF_INFRARED;
                        // TODO: gain_exp (chr, 300);
                        ch.PermanentStats1[StatTypes.Strength] += 2;
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Wisdom] += 1;
                        ch.PermanentStats1[StatTypes.Intelligence] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        ch1.MPMax += 1;
                        ch1.MPCurrent += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 459)
                    {
                        // TODO: gain_exp (chr, 450);
                        ch.PermanentStats1[StatTypes.Wisdom] += 3;
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Strength] += 1;
                        if (Rand.RandIntBetween(1, 2) == 2) ch.PermanentStats1[StatTypes.Constitution] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 467)
                    {
                        // TODO: gain_exp (chr, 700);
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(2, 5);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 2);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 468)
                    {
                        // TODO: gain_exp (chr, 500);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 5);
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 5);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 5);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 4);
                        ch.PermanentStats1[StatTypes.Dexterity] -= 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 497)
                    {
                        ch1.HPCurrent += 1;
                        ch1.HPMax += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 498)
                    {
                        ch1.MPCurrent += 1;
                        ch1.MPMax += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 469)
                    {
                        // TODO: gain_exp (chr, 450);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(2, 6);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(2, 6);
                        ch.PermanentStats1[StatTypes.Dexterity] += 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 482)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 2);
                        ch1.HPCurrent += 2;
                        ch1.HPMax += 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 481)
                    {
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 457)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 5);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 3);
                        ch1.MPMax += 1;
                        // TODO: gain_exp (chr, 250);
                        ch1.MPCurrent += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 483)
                    {
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 4);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 4);
                        ch1.HPMax += 2;
                        ch1.HPCurrent -= 2;
                        // TODO: gain_exp (chr, 300);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 484)
                    {
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 2);
                        ch1.MPMax += 1;
                        ch1.MPCurrent += 1;
                        // TODO: gain_exp (chr, 450);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 485)
                    {
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Strength] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 486)
                    {
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Strength] += 1;
                        ch.PermanentStats1[StatTypes.Constitution] += 1;
                        ch1.MPMax += 1;
                        ch1.MPCurrent += 1;

                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 488)
                    {
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 2);
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        // TODO: gain_exp (chr, 550);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 487)
                    {
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        // TODO: gain_exp (chr, 300);			       
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 466)
                    {
                        // TODO: gain_exp (chr, 100);
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(2, 4);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 492)
                    {
                        ch.PermanentStats1[StatTypes.Constitution] += 1;
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 491)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 2);
                        if (Rand.RandIntBetween(1, 2) == 2) ch.PermanentStats1[StatTypes.Constitution] += 1;
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 494)
                    {
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 3);
                        // TODO: gain_exp (chr, 650);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 493)
                    {
                        // TODO: gain_exp (chr, 320);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Intelligence] -= 2;
                        ch.learned[(int)GeneralSN.SlashingWeapons] = 22;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 476)
                    {
                        // TODO: gain_exp (chr, 400);
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        /*if (Rand.RandIntBetween(1,2)==2) nat_abilities|=AFF_INFRARED; */
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 475)
                    {
                        // TODO: gain_exp (chr, 200);
                        ch.PermanentStats1[StatTypes.Strength] += 2;
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Dexterity] += 2;
                        ch.PermanentStats1[StatTypes.Intelligence] += 2;
                        ch.PermanentStats1[StatTypes.Wisdom] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 479)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(2, 3);
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 480)
                    {
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(2, 3);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 477)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Dexterity] += Rand.RandIntBetween(1, 3);
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 478)
                    {
                        ch.PermanentStats1[StatTypes.Intelligence] += 1;
                        ch.PermanentStats1[StatTypes.Wisdom] += Rand.RandIntBetween(2, 4);
                        ch.PermanentStats1[StatTypes.Dexterity] += 1;
                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 496)
                    {
                        ch.PermanentStats1[StatTypes.Intelligence] += Rand.RandIntBetween(1, 2);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 2);
                        ch1.HPMax += 1;
                        ch1.HPCurrent += 1;
                        ch1.MPMax += 1;
                        ch1.MPCurrent += 1;

                        ch.EnforceRaceStatLimit(race);
                    }
                    else if (room.VnumRoom == 495)
                    {
                        ch.PermanentStats1[StatTypes.Strength] += Rand.RandIntBetween(1, 3);
                        ch.PermanentStats1[StatTypes.Constitution] += Rand.RandIntBetween(1, 4);
                        // TODO: gain_exp (chr, 410);
                        ch1.HPMax += 2;
                        ch1.HPCurrent += 2;
                        ch.learned[(int)GeneralSN.SlashingWeapons] = 18;
                        ch.EnforceRaceStatLimit(race);
                    }
                }
            }
        }

        /// <summary>
        /// Gets or sets the currentRoom the character is in.  This does
        /// no display-related functions, and it does not check
        /// permissions, etc
        /// </summary>
        public static RoomData GetInRoom(CharacterData ch)
        {
            if (ch.vnumInRoom == 0) return null;
            if (ch.InRoomInternal != null) return ch.InRoomInternal;
            if (WorldTemplates.htRooms.ContainsKey(ch.vnumInRoom) == true)
            {
                ch.InRoomInternal = WorldTemplates.htRooms[ch.vnumInRoom];
            }
            if (ch.InRoomInternal == null)
            {
                // TODO LogError("Room vnum " + ch.vnumInRoom.ToString() + " not found in Room list.", null, LogType.WorldError);
            }
            EmlenMud.AddCharacterToRoom(ch, ch.InRoomInternal);
            return ch.InRoomInternal;
        }

        public static void SetInRoom(CharacterData ch, RoomData value)
        {
            ch.InternalSetInRoomVnum(0);
            if (value == null)
            {
                if (ch.InRoomInternal != null)
                {
                    RemoveCharacterFromRoom(ch, ch.InRoomInternal);
                }
                ch.InRoomInternal = null;
            }
            else
            {
                if (ch.InRoomInternal != null)
                {
                    RemoveCharacterFromRoom(ch, ch.InRoomInternal);
                }
                ch.InRoomInternal = value;
                AddCharacterToRoom(ch, ch.InRoomInternal);
                ch.InternalSetInRoomVnum(value.VnumRoom);
            }
        }



        public static Spell FindSpell(string txt, int sn)
        {
            if (sn > 0) return (Spell)WorldTemplates.htSpellListByGSN[sn];
            if (txt == null) return null;
            if (txt != "")
            {
                Spell sp = (Spell)WorldTemplates.htSpellListByName[txt];
                if (sp != null) return sp;
                string compname = txt;
                sp = (Spell)WorldTemplates.htSpellListByName[compname];
                if (sp != null) return sp;
                // Otherwise we have to go through and search the list

                for (int i = 0; i < WorldTemplates.SpellList.Count; i++)
                {
                    sp = (Spell)WorldTemplates.SpellList[i];
                    if (sp.ShortName.StartsWith(txt, StringComparison.OrdinalIgnoreCase) == true)
                        return sp;
                }
            }
            return null;
        }

        public static Spell FindSpell(string cname)
        {
            return (Spell)WorldTemplates.htSpellListByName[cname];
        }

        /// <summary>
        /// Returns how one character looks to an other
        /// </summary>
        /// <param name="chrOther"></param>
        /// <returns></returns>
        public static string LookAt(CharacterData ch, CharacterData chrOther)
        {
            // HEREHERE: looking at another character or player
            StringBuilder sb = new StringBuilder(1024);
            if (ch.CanSee(chrOther) == false) return "";
            sb.Append("{Y}You see " + EmlenMud.ShortName(ch, chrOther));
            if (chrOther.position == CharPosition.standing)
            {
                sb.Append(" standing here.\n\r");
            }
            else
            {
                sb.Append(" here, " + chrOther.position.ToString() + ".\n\r");
            }

            string longDesc = chrOther.LongDescription;
            if (!string.IsNullOrEmpty(longDesc))
            {
                sb.Append(longDesc);
            }

            sb.Append("{W}More info will go here...");
            return sb.ToString();
        }

        public static StringBuilder FormatCodedString(CharacterData ch, CharacterData chrOther, StringBuilder sb)
        {
            StringBuilder sbReturn = sb.Replace("|ShortName", EmlenMud.ShortName(ch, chrOther));
            // Do other substitutions here
            return sbReturn;
        }

        public static StringBuilder FormatCodedString(CharacterData ch, CharacterData chrOther, string sz)
        {
            StringBuilder sb = new StringBuilder(sz);
            return FormatCodedString(ch, chrOther, sb);
        }

        public static int SendToOthersWhoCanSee(CharacterData ch, RoomData room, string sz)
        {
            int nCount = 0;
            if (room == null) return 0;
            if (room.HasCharacters == false) return 0;
            for (int i = 0; i < room.characters.Count; i++)
            {
                CharacterData chrWhoSees = (CharacterData)room.characters[i];
                if (chrWhoSees == ch) continue;
                if (!chrWhoSees.CanSee(ch)) continue;
                chrWhoSees.send_to_char(FormatCodedString(chrWhoSees, ch, sz).ToString());
                nCount++;
            }
            return nCount;
        }

        public static StringBuilder ListAllCommandsWithDesc(CharacterData ch)
        {
            StringBuilder sb = new StringBuilder(10000);
            int lvl = ch.Level;
#if NO_SILVERLIGHT
            if (ch.descriptor == null) return sb;
            if (ch.descriptor.UsingInterface != InterfaceType.HTML)
            {
                for (int i = 0; i < WorldTemplates.rgCommands.Count; i++)
                {
                    ICommand cmd = (ICommand)WorldTemplates.rgCommands[i];
                    if (cmd.NShortcut != 0) continue;
                    if (cmd.Level > lvl) continue;
                    sb.Append(cmd.Commandstring.PadRight(14, ' '));
                    sb.Append("Minimum Level: ");
                    sb.Append(cmd.Level.ToString().PadLeft(3));
                    sb.Append(", Position: ");
                    sb.Append(cmd.Position.ToString().PadRight(15));
                    sb.AppendLine(cmd.Descr);
                }
            }
            else
            {
                bool fImmort = ch.Immortal;
                //HtmlTable tbl = new System.Web.UI.HtmlControls.HtmlTable();
                //tbl.Width = "99%";
                //tbl.CellPadding = 2;
                //tbl.CellSpacing = 0;
                //tbl.Border = 0;
                //tbl.Style.Add(HtmlTextWriterStyle.BorderColor, "#CCFFCC");
                //tbl.Style.Add(HtmlTextWriterStyle.BorderStyle, "solid");
                //tbl.Style.Add(HtmlTextWriterStyle.BorderWidth, "2px");
                //HtmlTableRow HRow = new HtmlTableRow();
                //HRow.VAlign = "top";
                //HRow.Align = "left";
                //HRow.Style.Add(HtmlTextWriterStyle.FontWeight, "bold");
                //HRow.Style.Add(HtmlTextWriterStyle.Color, "#FFFFFF");
                //StaticHelpers.AddCell(HRow, "Command");
                //StaticHelpers.AddCell(HRow, "Level");
                //StaticHelpers.AddCell(HRow, "Position");
                ////if (fImmort == true) StaticHelpers.AddCell(HRow, "Function Name");
                //if (fImmort == true) StaticHelpers.AddCell(HRow, "Log Type");
                //StaticHelpers.AddCell(HRow, "Description");

                //tbl.Rows.Add(HRow);

                //for (int i = 0; i < WorldTemplates.rgCommands.Count; i++)
                //{
                //    ICommand cmd = (ICommand)WorldTemplates.rgCommands[i];
                //    if (cmd.NShortcut != 0) continue;
                //    if (cmd.Level > lvl) continue;
                //    HtmlTableRow tr = new HtmlTableRow();
                //    tr.Style.Add(HtmlTextWriterStyle.Color, "#EFEFEF");
                //    tr.VAlign = "top";
                //    tr.Align = "left";
                //    StaticHelpers.AddCell(tr, StaticHelpers.FirstLetterCap(cmd.Commandstring));
                //    StaticHelpers.AddCell(tr, cmd.Level.ToString());
                //    StaticHelpers.AddCell(tr, StaticHelpers.FirstLetterCap(cmd.Position.ToString()));
                //    //if (fImmort == true) StaticHelpers.AddCell(tr, cmd.commandfunction.Method.Name);
                //    if (fImmort == true) StaticHelpers.AddCell(tr, cmd.Logtype.ToString());
                //    StaticHelpers.AddCell(tr, cmd.Descr);
                //    tbl.Rows.Add(tr);
                //}

                //StringWriter swriter = new StringWriter(sb);
                //System.Web.UI.HtmlTextWriter tw = new System.Web.UI.HtmlTextWriter(swriter);
                //tbl.RenderControl(tw);
                //tw.Flush();
                //sb = swriter.GetStringBuilder();
                //sb.Insert(0, "<center>");
                //sb.Append("</center>");
                //sb.Replace("\n", "");
                //sb.Replace("\r", "");
            }
#endif
            return sb;
        }


    }

    public class StringCodeCollection : IStringCodeCollection
    {
        private ShowFlags showFlags;
        private ThreadSafeLookup<string, string> sCodeToString = new ThreadSafeLookup<string, string>();
        private ThreadSafeLookup<string, GetStringForCode> sCharCodeToStringFunction = new ThreadSafeLookup<string, GetStringForCode>();
        private ThreadSafeLookup<string, GetStringForCode> s3rdPersonCodeToStringFunction = new ThreadSafeLookup<string, GetStringForCode>();
        private ThreadSafeLookup<string, GetStringForCode> sTargetCodeToStringFunction = new ThreadSafeLookup<string, GetStringForCode>();

        // delegates / function pointers
        private GetStringForCode ShortNoun;
        private GetStringForCode NounSelf;
        private GetStringForCode HisHerIts;
        private GetStringForCode IsHisHersTheirs;
        private GetStringForCode HimHerIt;
        private GetStringForCode HeSheIt;


        /// <summary>
        /// Fill in the basic code substitutions
        /// </summary>
        private void InitializeBasicSubstitutions()
        {
            // Add the basics
            ShortNoun = CharName;
            NounSelf = AtSelf;
            HisHerIts = OwnershipAdjective;
            IsHisHersTheirs = Ownership;
            HimHerIt = YouHimHerIt;
            HeSheIt = ReferenceTo;
            sCharCodeToStringFunction.Add("|CName", ShortNoun);
            sCharCodeToStringFunction.Add("|CSelf", NounSelf);
            sCharCodeToStringFunction.Add("|CHisHerIts", HisHerIts);
            sCharCodeToStringFunction.Add("|CHimHerIt", HimHerIt);
            sCharCodeToStringFunction.Add("|CHeSheIt", HeSheIt);
            sCharCodeToStringFunction.Add("|CIsHisHersTheirs", IsHisHersTheirs);
            sTargetCodeToStringFunction.Add("|TName", ShortNoun);
            sTargetCodeToStringFunction.Add("|TSelf", NounSelf);
            sTargetCodeToStringFunction.Add("|THisHersIts", HisHerIts);
            sTargetCodeToStringFunction.Add("|THimHerIt", HimHerIt);
            sTargetCodeToStringFunction.Add("|THeSheIt", HeSheIt);
            sTargetCodeToStringFunction.Add("|TIsHisHersTheirs", IsHisHersTheirs);
            s3rdPersonCodeToStringFunction.Add("|3Name", ShortNoun);
            s3rdPersonCodeToStringFunction.Add("|3Self", NounSelf);
            s3rdPersonCodeToStringFunction.Add("|3HisHersIts", HisHerIts);
            s3rdPersonCodeToStringFunction.Add("|3HimHerIt", HimHerIt);
            s3rdPersonCodeToStringFunction.Add("|3HeSheIt", HeSheIt);
            s3rdPersonCodeToStringFunction.Add("|3IsHisHersTheirs", IsHisHersTheirs);
            sCharCodeToStringFunction.Add("$n", ShortNoun);
            sCharCodeToStringFunction.Add("$e", HeSheIt);
            sCharCodeToStringFunction.Add("$s", HisHerIts);
            sCharCodeToStringFunction.Add("$m", HimHerIt);
            sTargetCodeToStringFunction.Add("$N", ShortNoun);
            sTargetCodeToStringFunction.Add("$E", HeSheIt);
            sTargetCodeToStringFunction.Add("$S", HisHerIts);
            sTargetCodeToStringFunction.Add("$M", HimHerIt);
        }

        public StringCodeCollection()
        {
            showFlags = ShowFlags.None;
            InitializeBasicSubstitutions();
        }

        public StringCodeCollection(ShowFlags showFlagsIn)
        {
            showFlags = showFlagsIn;
            InitializeBasicSubstitutions();
        }

        public ShowFlags ShowOptions
        {
            get { return showFlags; }
            set { showFlags = value; }
        }

        public bool IsShowFlagSet(DisplaysTo disp1, DisplaysTo disp2) { return ((int)disp1 & (int)disp2) != 0; }
        public bool this[ShowFlags flags]
        {
            get { return ((int)flags & (int)showFlags) != 0; }
            set { if (value == true) showFlags |= flags; else showFlags &= (~flags); }
        }

        public ThreadSafeLookup<string, string> SubstitutionsAndCodes
        {
            get { return sCodeToString; }
            set { sCodeToString = value; }
        }

        public ThreadSafeLookup<string, GetStringForCode> FunctionsForInterprettingCHARACTERCodeStrings
        {
            get { return sCharCodeToStringFunction; }
            set { sCharCodeToStringFunction = value; }
        }

        public ThreadSafeLookup<string, GetStringForCode> FunctionsForInterprettingTARGETCodeStrings
        {
            get { return sTargetCodeToStringFunction; }
            set { sTargetCodeToStringFunction = value; }
        }

        public ThreadSafeLookup<string, GetStringForCode> FunctionsForInterprettingTHIRDPERSONCodeStrings
        {
            get { return s3rdPersonCodeToStringFunction; }
            set { s3rdPersonCodeToStringFunction = value; }
        }

        public GetStringForCode ShortNounDelegate
        {
            get { return ShortNoun; }
            set { ShortNoun = value; }
        }

        public GetStringForCode SelfNounDelegate
        {
            get { return NounSelf; }
            set { NounSelf = value; }
        }

        public GetStringForCode HisHersItsDelegate
        {
            get { return HisHerIts; }
            set { HisHerIts = value; }
        }

        public GetStringForCode IsHisHersTheirsDelegate
        {
            get { return IsHisHersTheirs; }
            set { IsHisHersTheirs = value; }
        }

        public GetStringForCode HimHerItDelegate
        {
            get { return HimHerIt; }
            set { HimHerIt = value; }
        }

        public GetStringForCode HeSheItDelegate
        {
            get { return HeSheIt; }
            set { HeSheIt = value; }
        }


        // The basic / standard functions pointed to by the delegates
        public string CharName(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (ch == looker) return "you";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "someone" : shownIfCantSee;
            }
            return EmlenMud.ShortName(looker, ch);
        }

        public string AtSelf(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (looker == ch) return "yourself";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "itself" : shownIfCantSee;
            }
            return ch.Him_Her_It + "self";
        }

        public string OwnershipAdjective(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (looker == ch) return "your";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "its" : shownIfCantSee;
            }
            return ch.His_Hers_Its;
        }

        public string Ownership(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (looker == ch) return "yours";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "theirs" : shownIfCantSee;
            }
            return ch.His_Hers_Theirs;
        }

        public string YouHimHerIt(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (looker == ch) return "you";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "it" : shownIfCantSee;
            }
            return ch.Him_Her_It;
        }

        public string ReferenceTo(CharacterData ch, CharacterData looker, string shownIfCantSee, ShowFlags flags)
        {
            if (looker == ch) return "you";
            if (!looker.CanSee(ch))
            {
                if (this[flags]) return "";
                return (string.IsNullOrEmpty(shownIfCantSee)) ? "it" : shownIfCantSee;
            }
            return ch.He_She_It;
        }


        /// <summary>
        /// The powerhouse, ultra-flexible string-code translator -- translates
        /// a string code into a meaningful, grammatically string for a single
        /// character.
        /// </summary>
        /// <param name="sbWorkspace">The StringBuilder containing the coded string</param>
        /// <param name="performingCharacter">Character considered performing the action</param>
        /// <param name="targetOfAction">Character considered the "targetOfAction" of the action</param>
        /// <param name="thirdPartyInvolvedInAction">A third party involved in the action</param>
        /// <param name="chLooker">The character who is looking at this action being performed</param>
        /// <param name="rgfContainsCharKeys">Which keys we need to look for</param>
        /// <param name="rgfContainsTargetKeys">Which keys we need to look for</param>
        /// <param name="rgfContains3PKeys">Which keys we need to look for</param>
        /// <param name="performingCharacterNameIfViewerCantSee">The Character Name to show if the looker can't see the character</param>
        /// <param name="targetCharacterNameIfViewerCantSee">The Target Name to show if the looker can't see the targetOfAction</param>
        /// <returns>A stringbuilder containing the substituted string</returns>
        private StringBuilder DoSubstitutionForSingleCharacter(StringBuilder sbWorkspace,
              CharacterData ch, CharacterData target, CharacterData chThird, CharacterData chLooker,
              ThreadSafeLookupNonRef<string, bool> rgfContainsCharKeys, ThreadSafeLookupNonRef<string, bool> rgfContainsTargetKeys,
              ThreadSafeLookupNonRef<string, bool> rgfContains3PKeys, string sCharNameIfLookerCantSee, string sTargetNameIfLookerCantSee)
        {
            bool fSkip = false;
            if (ch != null)
            {
                foreach (KeyValuePair<string, GetStringForCode> keyAndValue in sCharCodeToStringFunction)
                {
                    if (rgfContainsCharKeys.ContainsKey(keyAndValue.Key))
                    {
                        string sKey = keyAndValue.Key;
                        GetStringForCode fn = keyAndValue.Value;
                        string sz = fn.Invoke(ch, chLooker,
                          sCharNameIfLookerCantSee,
                          (ShowFlags.ShowNothingToThoseWhoCantSeeChr & showFlags));
                        if (sz == "")
                        {
                            fSkip = true;
                            break;
                        }

                        sbWorkspace = sbWorkspace.Replace(sKey, sz);
                    }
                }
            }
            if (!fSkip)
            {
                if (target != null)
                {
                    foreach (KeyValuePair<string, GetStringForCode> keyAndValue in sTargetCodeToStringFunction)
                    {
                        if (rgfContainsTargetKeys.ContainsKey(keyAndValue.Key))
                        {
                            string sKey = keyAndValue.Key;
                            GetStringForCode fn = keyAndValue.Value;
                            string sz = fn.Invoke(target, chLooker,
                                sTargetNameIfLookerCantSee,
                                (ShowFlags.ShowNothingToThoseWhoCantSeeTarget & showFlags));
                            if (sz == "")
                            {
                                fSkip = true;
                                break;
                            }
                            sbWorkspace = sbWorkspace.Replace(sKey, sz);
                        }
                    }
                }
            }
            if (!fSkip && chThird != null)
            {
                if (ch != null && target != null)
                {
                    foreach (KeyValuePair<string, GetStringForCode> keyAndValue in s3rdPersonCodeToStringFunction)
                    {
                        if (rgfContains3PKeys.ContainsKey(keyAndValue.Key))
                        {
                            string sKey = keyAndValue.Key;
                            GetStringForCode fn = keyAndValue.Value;
                            string sz = fn.Invoke(chThird, chLooker,
                                sTargetNameIfLookerCantSee,
                                (ShowFlags.ShowNothingToThoseWhoCantSeeTarget & showFlags));
                            if (sz == "")
                            {
                                fSkip = true;
                                break;
                            }
                            sbWorkspace = sbWorkspace.Replace(sKey, sz);
                        }
                    }
                }
            }
            return (fSkip ? null : sbWorkspace);
        }

        /// <summary>
        /// Capitalizes the first character of a stringbuilder, but ignoring
        /// leading codes and color brackets/etc
        /// </summary>
        /// <param name="sbWorkspace"></param>
        /// <returns></returns>
        public StringBuilder CapFirstLetter(StringBuilder sbWorkspace)
        {
            int nBracket = 0;
            for (int i = 0; i < sbWorkspace.Length; i++)
            {
                if (sbWorkspace[i] == '{') nBracket++;
                else if (sbWorkspace[i] == '}') nBracket--;
                else if (nBracket == 0)
                {
                    sbWorkspace[i] = char.ToUpper(sbWorkspace[i]);
                    break;
                }
            }
            return sbWorkspace;
        }

        /// <summary>
        /// Translates and then displays a coded string to the appropriate characters
        /// </summary>
        /// <param name="displayTo"></param>
        /// <param name="sbCodedString"></param>
        /// <param name="performingCharacter"></param>
        /// <param name="targetOfAction"></param>
        /// <param name="thirdPartyInvolvedInAction"></param>
        /// <param name="multipleOtherTargetCharacters"></param>
        /// <param name="performingCharacterNameIfViewerCantSee"></param>
        /// <param name="targetCharacterNameIfViewerCantSee"></param>
        public void DisplayCodedStringTo(DisplaysTo displayTo, StringBuilder sbCodedString,
          CharacterData performingCharacter, CharacterData targetOfAction, CharacterData thirdPartyInvolvedInAction,
          List<CharacterData> multipleOtherTargetCharacters,
          string performingCharacterNameIfViewerCantSee,
          string targetCharacterNameIfViewerCantSee)
        {
            DisplayCodedStringTo(displayTo, sbCodedString.ToString(), performingCharacter, targetOfAction, thirdPartyInvolvedInAction, multipleOtherTargetCharacters,
              performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
      CharacterData performingCharacter, CharacterData targetOfAction, CharacterData thirdPartyInvolvedInAction,
      string performingCharacterNameIfViewerCantSee,
      string targetCharacterNameIfViewerCantSee)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, targetOfAction, thirdPartyInvolvedInAction, null,
              performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter, CharacterData targetOfAction,
          string performingCharacterNameIfViewerCantSee,
          string targetCharacterNameIfViewerCantSee)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, targetOfAction, null, null,
              performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter,
          string performingCharacterNameIfViewerCantSee)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, null, null, null,
              performingCharacterNameIfViewerCantSee, "");
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter, CharacterData targetOfAction, CharacterData thirdPartyInvolvedInAction)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, targetOfAction, thirdPartyInvolvedInAction, null, "", "");
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter, CharacterData targetOfAction)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, targetOfAction, null, null, "", "");
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, null, null, null, "", "");
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
        CharacterData performingCharacter, CharacterData targetOfAction, CharacterData thirdPartyInvolvedInAction,
        List<CharacterData> multipleOtherTargetCharacters)
        {
            DisplayCodedStringTo(displayTo, sCodedString.ToString(), performingCharacter, targetOfAction, thirdPartyInvolvedInAction, multipleOtherTargetCharacters, "", "");
        }

        public void DisplayCodedStringTo(DisplaysTo displayTo, string sCodedString,
          CharacterData performingCharacter, CharacterData targetOfAction, CharacterData thirdPartyInvolvedInAction,
          List<CharacterData> multipleOtherTargetCharacters,
          string performingCharacterNameIfViewerCantSee,
          string targetCharacterNameIfViewerCantSee)
        {
            StringBuilder sbBase = new StringBuilder(sCodedString.Length + 1024);
            sbBase.Append(sCodedString);
            bool fCapitalizeFirstLetter = (sCodedString[0] == '|') || (sCodedString[0] == '$');
            if (sCodedString[0] == '{')
            {
                for (int i = 0; i < 9 && i < sCodedString.Length - 1; i++)
                {
                    if (sCodedString[i] == '}' &&
                        (sCodedString[i + 1] == '|' || sCodedString[i + 1] == '$'))
                    {
                        fCapitalizeFirstLetter = true;
                        break;
                    }
                }
            }
            foreach (KeyValuePair<string, string> keyAndValue in sCodeToString)
            {
                sbBase = sbBase.Replace(keyAndValue.Key, keyAndValue.Value);
            }

            ThreadSafeLookupNonRef<string, bool> rgfContainsCharKeys = new ThreadSafeLookupNonRef<string, bool>();
            foreach (KeyValuePair<string, GetStringForCode> keyAndValue in sCharCodeToStringFunction)
            {
                if (sCodedString.IndexOf(keyAndValue.Key, StringComparison.Ordinal) >= 0)
                {
                    rgfContainsCharKeys.Add(keyAndValue.Key, true);
                }
            }
            ThreadSafeLookupNonRef<string, bool> rgfContainsTargetKeys = new ThreadSafeLookupNonRef<string, bool>();
            foreach (KeyValuePair<string, GetStringForCode> keyAndValue in sTargetCodeToStringFunction)
            {
                if (sCodedString.IndexOf(keyAndValue.Key, StringComparison.Ordinal) >= 0)
                {
                    rgfContainsTargetKeys.Add(keyAndValue.Key, true);
                }
            }
            ThreadSafeLookupNonRef<string, bool> rgfContains3PKeys = new ThreadSafeLookupNonRef<string, bool>();
            foreach (KeyValuePair<string, GetStringForCode> keyAndValue in s3rdPersonCodeToStringFunction)
            {
                if (sCodedString.IndexOf(keyAndValue.Key, StringComparison.Ordinal) >= 0)
                {
                    rgfContains3PKeys.Add(keyAndValue.Key, true);
                }
            }

            StringBuilder sbWorkspace = new StringBuilder(sbBase.Length + 1024);

            if (IsShowFlagSet(displayTo, DisplaysTo.chInitiated) && performingCharacter != null)
            {
                sbWorkspace.Length = 0;
                sbWorkspace.Append(sbBase.ToString());
                StringBuilder sbRet = DoSubstitutionForSingleCharacter(sbWorkspace,
                  performingCharacter, targetOfAction, thirdPartyInvolvedInAction, performingCharacter, rgfContainsCharKeys, rgfContainsTargetKeys, rgfContains3PKeys,
                  performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
                if (sbRet != null)
                {
                    if (fCapitalizeFirstLetter) sbWorkspace = CapFirstLetter(sbWorkspace);
                    sbWorkspace.Replace("(s)", "");
                    performingCharacter.send_to_char(sbWorkspace.ToString());
                }
            }

            if (IsShowFlagSet(displayTo, DisplaysTo.Target) && targetOfAction != null)
            {
                sbWorkspace.Length = 0;
                sbWorkspace.Append(sbBase.ToString());
                StringBuilder sbRet = DoSubstitutionForSingleCharacter(sbWorkspace,
                  performingCharacter, targetOfAction, thirdPartyInvolvedInAction, targetOfAction, rgfContainsCharKeys, rgfContainsTargetKeys, rgfContains3PKeys,
                  performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
                if (sbRet != null)
                {
                    if (fCapitalizeFirstLetter) sbWorkspace = CapFirstLetter(sbWorkspace);
                    sbWorkspace.Replace("(s)", "s");
                    targetOfAction.send_to_char(sbWorkspace.ToString());
                }
            }

            sbWorkspace.Length = 0;
            sbWorkspace.Append(sbBase.ToString());

            if (IsShowFlagSet(displayTo, DisplaysTo.AllTargets))
            {
                if (multipleOtherTargetCharacters != null)
                {
                    foreach (CharacterData chLooker in multipleOtherTargetCharacters)
                    {
                        StringBuilder sbRet = DoSubstitutionForSingleCharacter(sbWorkspace,
                        performingCharacter, targetOfAction, thirdPartyInvolvedInAction, chLooker, rgfContainsCharKeys, rgfContainsTargetKeys, rgfContains3PKeys,
                        performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
                        if (sbRet != null)
                        {
                            if (fCapitalizeFirstLetter) sbWorkspace = CapFirstLetter(sbWorkspace);
                            sbWorkspace.Replace("(s)", "s");
                            chLooker.send_to_char(sbWorkspace.ToString());
                        }
                        sbWorkspace.Length = 0;
                        sbWorkspace.Append(sbBase.ToString());
                    }
                }
            }

            RoomData[] rgRooms = new RoomData[2];
            if (IsShowFlagSet(displayTo, DisplaysTo.BystandersInCharRoom))
            {
                if (performingCharacter != null) { rgRooms[0] = EmlenMud.GetInRoom(performingCharacter); } else rgRooms[0] = null;
            }
            if (IsShowFlagSet(displayTo, DisplaysTo.BystandersInTargetRoom))
            {
                if (targetOfAction != null) { rgRooms[1] = EmlenMud.GetInRoom(targetOfAction); } else rgRooms[1] = null;
            }
            for (int i = 0; i < 2; i++)
            {
                if (rgRooms[i] == null) continue;
                RoomData room = rgRooms[i];
                if ((room != null) && room.HasCharacters)
                {
                    for (int j = 0; j < room.characters.Count; j++)
                    {
                        // Check if not in the targetOfAction list or the targetOfAction or the character
                        CharacterData chLooker = room.characters[j];
                        if (chLooker == performingCharacter || chLooker == targetOfAction) continue;
                        if (multipleOtherTargetCharacters != null)
                        {
                            if (multipleOtherTargetCharacters.Contains(chLooker) == true) continue;
                        }

                        StringBuilder sbRet = DoSubstitutionForSingleCharacter(sbWorkspace,
                        performingCharacter, targetOfAction, thirdPartyInvolvedInAction, chLooker, rgfContainsCharKeys, rgfContainsTargetKeys, rgfContains3PKeys,
                        performingCharacterNameIfViewerCantSee, targetCharacterNameIfViewerCantSee);
                        if (sbRet != null)
                        {
                            if (fCapitalizeFirstLetter) sbWorkspace = CapFirstLetter(sbWorkspace);
                            sbWorkspace.Replace("(s)", "s");
                            chLooker.send_to_char(sbWorkspace.ToString());
                        }

                        sbWorkspace.Length = 0;
                        sbWorkspace.Append(sbBase.ToString());
                    }
                }
            }
        }
    }

    public class PersistentWorldData //: IPersistentWorldData
    {
        public PersistentWorldData()
        {
            arealst = (AreaList)new AreaList();
            topten = new TopTenData();
            ratings = new RatingData();
            LimitedItems = new LimitedItemsData();
            AllGuilds = new GuildList();
        }

        public AreaData FindArea(string cn)
        {
            for (int i = 0; i < AllAreas.Count; i++)
            {
                AreaData ar = (AreaData)AllAreas[i];
                if (ar.ShortName == cn) return (AreaData)ar;
            }
            return null;
        }

        //public AreaData FindArea(string szFN)
        //{
        //    for (int i = 0; i < AllAreas.Count; i++)
        //    {
        //        AreaData ar = (AreaData)AllAreas[i];
        //        if (ar.AreaFileName.Equals(szFN, StringComparison.OrdinalIgnoreCase) == true) return (AreaData)ar;
        //    }
        //    return null;
        //}

        public AreaData SerializeAreaIn(string szFileName, int inVersion)
        {
#if NO_SILVERLIGHT
            string szFName = EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.AREA_DIR + "\\" + szFileName + "." + typeof(AreaData).Name.ToString() + inVersion.ToString();
            Object o = SerializationHelper.SerializeObjectIn(szFName);
            if (o == null) return null;
            if (o is AreaData)
            {
                // EmlenMud.OutputMessage("Read " + szFileName);
                AreaData area = (AreaData)o;
                //area.syncRooms = new ReaderWriterLock();
                //area.AssignEmlenMud(EmlenMud);
                area.AreaFileName = szFileName;
                EmlenMud.WorldTemplates.AllAreas.Add(area);
                EmlenMud.WorldTemplates.nAreaCount++;
                if (area.OpenToPlayers > 0) EmlenMud.WorldTemplates.open_areas++;

                // Take care of mob prototypes first
                for (int i = area.MobPrototypesBelongingToArea.Count - 1; i >= 0; i--)
                {
                    MobPrototype mproto = (MobPrototype)area.MobPrototypesBelongingToArea[i];
                    //mproto.AssignEmlenMud(EmlenMud);
                    if (EmlenMud.WorldTemplates.AllMobPrototypes.ContainsKey(mproto.Vnum) == true)
                    {
                        EmlenMud.LogError("Duplicate Mob Prototype in area " + area.ShortName + " (vnum " + mproto.Vnum.ToString() + ")", null, LogType.WorldError);
                        area.MobPrototypesBelongingToArea.RemoveAt(i);
                        continue;
                    }
                    if (mproto.Vnum > EmlenMud.WorldTemplates.top_vnum_mob_prototype) EmlenMud.WorldTemplates.top_vnum_mob_prototype = mproto.Vnum;
                    EmlenMud.WorldTemplates.AllMobPrototypes[mproto.Vnum] = mproto;
                    EmlenMud.WorldTemplates.nMobPrototypes++;
                    if (mproto.PShop != null)
                    {
                        //((ShopData)mproto.PShop).AssignEmlenMud(EmlenMud);
                        EmlenMud.WorldTemplates.AllShops.Add(mproto.PShop);
                    }
                }
                // next objects
                for (int i = area.ObjectPrototypesBelongingToArea.Count - 1; i >= 0; i--)
                {
                    ObjectPrototype oproto = (ObjectPrototype)area.ObjectPrototypesBelongingToArea[i];
                    //oproto.AssignEmlenMud(EmlenMud);
                    if (EmlenMud.WorldTemplates.AllObjPrototypes.ContainsKey(oproto.Vnum) == true)
                    {
                        EmlenMud.LogError(
                          "Duplicate Object Prototype in area " + area.ShortName + " (vnum " + oproto.Vnum.ToString() + ")", null, LogType.WorldError);
                        area.ObjectPrototypesBelongingToArea.RemoveAt(i);
                        continue;
                    }

                    EmlenMud.WorldTemplates.AllObjPrototypes[oproto.Vnum] = oproto;
                    EmlenMud.WorldTemplates.nObjectPrototypes++;
                    if (oproto.Vnum > EmlenMud.WorldTemplates.top_vnum_obj_prototype) EmlenMud.WorldTemplates.top_vnum_obj_prototype = oproto.Vnum;
                }

                // next rooms
                for (int i = area.RoomsInArea.Count - 1; i >= 0; i--)
                {
                    RoomData room = (RoomData)area.RoomsInArea[i];
                    //room.AssignEmlenMud(EmlenMud);
                    if (EmlenMud.WorldTemplates.htRooms.ContainsKey(room.VnumRoom) == true)
                    {
                        EmlenMud.LogError("Duplicate Room vnum in area " + area.ShortName + " (vnum " + room.VnumRoom.ToString() + ")", null, LogType.WorldError);
                        area.RoomsInArea.RemoveAt(i);
                        continue;
                    }
                    EmlenMud.WorldTemplates.htRooms[room.VnumRoom] = room;

                    EmlenMud.WorldTemplates.nRoomsOpen++;
                    if (room.VnumRoom > EmlenMud.WorldTemplates.top_room_vnum) EmlenMud.WorldTemplates.top_room_vnum = room.VnumRoom;
                }
                return area;
            }
#endif
            return null;
        }

        public bool SerializeAreaOut(AreaData areaI, int outVersion)
        {
#if NO_SILVERLIGHT
            AreaData area = (AreaData)areaI;
            //if (area.EmlenMud == null) area.AssignEmlenMud(EmlenMud);
            string szFName = EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.AREA_DIR + "\\" + area.AreaFileName.ToString() + "." + typeof(AreaData).Name.ToString() + outVersion.ToString();
            return SerializationHelper.SerializeObjectOut(area, szFName, true);
#else
            return true;
#endif
        }

        public AreaData CreateNewArea(int nApproximateRoomVnums, string szAreaName, string szFileName, int nOpen)
        {
            AreaData area = new AreaData();
            area.Name = new NameAndDescription() { Name = szAreaName, FriendlyUniqueName = szAreaName };
            int nStartVnum = 1;
            if (EmlenMud.WorldTemplates.top_room_vnum > 0)
            {
                nStartVnum = EmlenMud.WorldTemplates.top_room_vnum + 1000;
            }
            int nEndVnum = nStartVnum + nApproximateRoomVnums;
            area.AreaFileName = szFileName;
            area.OpenToPlayers = nOpen;
            area.LowestVnumBelongingToArea = nStartVnum;
            area.HighestVnumBelongingToArea = nEndVnum;
            area.AddNewRoom();
            if (EmlenMud.WorldTemplates.arealist.AddAreaToList(area) == false)
            {
                // duplicate file name
                return null;
            }

            EmlenMud.WorldTemplates.AllAreas.Add(area);
            EmlenMud.WorldTemplates.nAreaCount++;
            if (area.OpenToPlayers > 0) EmlenMud.WorldTemplates.open_areas++;
            return area;
        }

        // Socials
        private List<SocialData> rgAllSoc = new List<SocialData>();
        private ThreadSafeLookup<string, SocialData> htAllSoc = new ThreadSafeLookup<string, SocialData>();

        public List<SocialData> AllSocials { get { return rgAllSoc; } set { rgAllSoc = value; } }
        public ThreadSafeLookup<string, SocialData> htSocialsByName { get { return htAllSoc; } set { htAllSoc = value; } }

        private List<ObjectPop> rgObjRandPopI = new List<ObjectPop>();
        //private Hashtable nMobPopC = new Hashtable(128);

        public List<ObjectPop> rgObjRandPopInfo { get { return rgObjRandPopI; } set { rgObjRandPopI = value; } }
        //public Hashtable nMobPopCount { get { return nMobPopC; } set { nMobPopC = value; } }

        // Configuration and power settings
        private IPowerData pwr;
        public IPowerData pow { get { return pwr; } set { pwr = value; } }

        // Actual list of channels (ChannelData)
        private List<ChannelData> rgChanls = new List<ChannelData>();
        public List<ChannelData> channels { get { return rgChanls; } set { rgChanls = value; } }

        private TimeSpan arenaTL;
        public TimeSpan arenaTimelimit { get { return arenaTL; } set { arenaTL = value; } }

        //public Hashtable htQByName = new Hashtable(32);	// of QuestData
        //public Hashtable htQuestsByName { get { return htQByName; } set { htQByName = value; } }

        // Rating and Top Ten
        private TopTenData tten;
        public ITopTenData topten { get { return tten; } set { tten = (TopTenData)value; } }
        private RatingData rtngs;
        public IRatingData ratings { get { return rtngs; } set { rtngs = (RatingData)value; } }

        // Spells and skills
        private List<Spell> SList = new List<Spell>();
        public List<Spell> SpellList { get { return SList; } set { SList = value; } }
        private ThreadSafeLookup<string, Spell> htSByName = new ThreadSafeLookup<string, Spell>();
        public ThreadSafeLookup<string, Spell> htSpellListByName { get { return htSByName; } set { htSByName = value; } }
        private ThreadSafeLookup<int, Spell> htSByGSN = new ThreadSafeLookup<int, Spell>();
        public ThreadSafeLookup<int, Spell> htSpellListByGSN { get { return htSByGSN; } set { htSByGSN = value; } }
        private int topspell = 0;
        public int nSpellCount { get { return topspell; } set { topspell = value; } }

        // Playerbase data
        private ThreadSafeLookup<string, PlayerbaseData> htPbase = new ThreadSafeLookup<string, PlayerbaseData>();
        public ThreadSafeLookup<string, PlayerbaseData> htPlayerbase { get { return htPbase; } set { htPbase = value; } }
        private List<PlayerbaseData> rgPbase = new List<PlayerbaseData>();
        public List<PlayerbaseData> rgPlayerbase { get { return rgPbase; } set { rgPbase = value; } }

        // Notes
        private List<NoteData> AlNotes = new List<NoteData>();
        public List<NoteData> AllNotes { get { return AlNotes; } set { AlNotes = value; } }

        // Mob Prototypes by vnumClan
        private ThreadSafeLookup<int, MobPrototype> AlMobPrototypes = new ThreadSafeLookup<int, MobPrototype>();
        public ThreadSafeLookup<int, MobPrototype> AllMobPrototypes { get { return AlMobPrototypes; } set { AlMobPrototypes = value; } }
        private int nMbPrototypes = 0;
        public int nMobPrototypes { get { return nMbPrototypes; } set { nMbPrototypes = value; } }
        private int tp_vnum_mob_prototype = 0;
        public int top_vnum_mob_prototype { get { return tp_vnum_mob_prototype; } set { tp_vnum_mob_prototype = value; } }

        // Obj Prototypes by vnumClan
        private ThreadSafeLookup<int, ObjectPrototype> AlObjPrototypes = new ThreadSafeLookup<int, ObjectPrototype>();
        public ThreadSafeLookup<int, ObjectPrototype> AllObjPrototypes { get { return AlObjPrototypes; } set { AlObjPrototypes = value; } }
        private int nObjctPrototypes = 0;
        public int nObjectPrototypes { get { return nObjctPrototypes; } set { nObjctPrototypes = value; } }
        private int tp_vnum_obj_prototype = 0;
        public int top_vnum_obj_prototype { get { return tp_vnum_obj_prototype; } set { tp_vnum_obj_prototype = value; } }

        // Limited object data
        private ILimitedItemsData LmitedItems;
        public ILimitedItemsData LimitedItems { get { return LmitedItems; } set { LmitedItems = value; } }

        // Rooms by vnumClan
        private ThreadSafeLookup<int, RoomData> htRms = new ThreadSafeLookup<int, RoomData>();
        public ThreadSafeLookup<int, RoomData> htRooms { get { return htRms; } set { htRms = value; } }
        private int nRmsOpen = 0;
        public int nRoomsOpen { get { return nRmsOpen; } set { nRmsOpen = value; } }
        private int tp_room_vnum = 0;
        public int top_room_vnum { get { return tp_room_vnum; } set { tp_room_vnum = value; } }

        public RoomData GetRoom(int vnum)
        {
            if (htRooms.ContainsKey(vnum) == false) return null;
            else return htRooms[vnum];
        }

        // TODO: HEREHERE: Fill this in
        private IGuildList AlGuilds;
        public IGuildList AllGuilds { get { return AlGuilds; } set { AlGuilds = value; } }

        // Clans 
        private List<ClanData> AlClans = new List<ClanData>();
        public List<ClanData> AllClans { get { return AlClans; } set { AlClans = value; } }

        // Clans 
        private List<ClanData> AlSects = new List<ClanData>();
        public List<ClanData> AllSects { get { return AlSects; } set { AlSects = value; } }

        // Shops
        private List<ShopData> AlShops = new List<ShopData>();
        public List<ShopData> AllShops { get { return AlShops; } set { AlShops = value; } }

        // Everyone in the player base (including those not loaded into memory)
        private List<PlayerbaseData> AlPlayerbaseData = new List<PlayerbaseData>();
        public List<PlayerbaseData> AllPlayerbaseData { get { return AlPlayerbaseData; } set { AlPlayerbaseData = value; } }

        // Race Data
        private List<RaceData> AlRaces = new List<RaceData>();
        public List<RaceData> AllRaces { get { return AlRaces; } set { AlRaces = value; } }

        // Help topics
        private List<HelpData> AlHelpTopics = new List<HelpData>();
        public List<HelpData> AllHelpTopics { get { return AlHelpTopics; } set { AlHelpTopics = value; } }

        // Commands
        private List<ICommand> rgCmmands = new List<ICommand>(128);
        public List<ICommand> rgCommands { get { return rgCmmands; } set { rgCmmands = value; } }

        private ThreadSafeLookup<string, ICommand> htCmmands = new ThreadSafeLookup<string, ICommand>();
        public ThreadSafeLookup<string, ICommand> htCommands { get { return htCmmands; } set { htCmmands = value; } }

        private ThreadSafeLookup<int, List<ICommand>> htCmmandListsByFirstTwoLetters = new ThreadSafeLookup<int, List<ICommand>>();
        public ThreadSafeLookup<int, List<ICommand>> htCommandListsByFirstTwoLetters { get { return htCmmandListsByFirstTwoLetters; } set { htCmmandListsByFirstTwoLetters = value; } }

        // Area Data
        // list of area file names
        private AreaList arealst;
        public AreaList arealist { get { return arealst; } set { arealst = value; } }
        private List<AreaData> AlAreas = new List<AreaData>();  // Stores the actual AreaData
        public List<AreaData> AllAreas { get { return AlAreas; } set { AlAreas = value; } }
        private int opn_areas = 0;
        public int open_areas { get { return opn_areas; } set { opn_areas = value; } }
        private int nAreaCnt = 0;
        public int nAreaCount { get { return nAreaCnt; } set { nAreaCnt = value; } }

        // Banned IP addresses
        private ThreadSafeLookup<string, BanData> banlist = new ThreadSafeLookup<string, BanData>();
        public ThreadSafeLookup<string, BanData> ban_list { get { return banlist; } set { banlist = value; } }

        // Score-command template
        public string score_template = "score.dat was not found!";
        public string sh_score_template = "sh_score.dat was not found!";

        public void bansite(string sz)
        {
            BanData b = (BanData)ban_list[sz];
            if (b == null)
            {
                b = new BanData();
                b.NameOfSite = sz;
                b.Newbie = false;
                ban_list.Add(sz, b);
            }
            else
            {
                b.Newbie = false;
            }
        }

        public void nbansite(string sz)
        {
            BanData b = (BanData)ban_list[sz];
            if (b == null)
            {
                b = new BanData();
                b.NameOfSite = sz;
                b.Newbie = true;
                ban_list.Add(sz, b);
            }
            else
            {
                b.Newbie = true;
            }
        }


        public void InsertBasicSkills()
        {
            if (htSpellListByGSN[(int)GeneralSN.Laser] == null) { Spell spell = new Spell(0, GeneralSN.Laser, "Blasting Weapons", "Blasting Weapons"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.BodySlam] == null) { Spell spell = new Spell(0, GeneralSN.BodySlam, "Bodyslam", "Bodyslam"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Disembowel] == null) { Spell spell = new Spell(0, GeneralSN.Disembowel, "Disembowel", "Disembowel"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Tap] == null) { Spell spell = new Spell(0, GeneralSN.Tap, "Tap", "Tap"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Elbow] == null) { Spell spell = new Spell(0, GeneralSN.Elbow, "Elbow", "Elbow"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Headbutt] == null) { Spell spell = new Spell(0, GeneralSN.Headbutt, "Headbutt", "Headbutt"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Berserk] == null) { Spell spell = new Spell(0, GeneralSN.Berserk, "Berserk", "Berserk"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.PrimalGrunt] == null) { Spell spell = new Spell(0, GeneralSN.PrimalGrunt, "Primal Grunt", "Primal Grunt"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Investigation] == null) { Spell spell = new Spell(0, GeneralSN.Investigation, "Investigation", "Investigation"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Riding] == null) { Spell spell = new Spell(0, GeneralSN.Riding, "Riding", "Riding"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Circle] == null) { Spell spell = new Spell(0, GeneralSN.Circle, "Circle", "Circle"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.ArmorPenetration] == null) { Spell spell = new Spell(0, GeneralSN.ArmorPenetration, "Armor Penetration", "Armor Penetration"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Swim] == null) { Spell spell = new Spell(0, GeneralSN.Swim, "Swim", "Swim"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Butcher] == null) { Spell spell = new Spell(0, GeneralSN.Butcher, "Butcher", "Butcher"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Backstab] == null) { Spell spell = new Spell(0, GeneralSN.Backstab, "Backstab", "Backstab"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Dodge] == null) { Spell spell = new Spell(0, GeneralSN.Dodge, "Dodge", "Dodge"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Hide] == null) { Spell spell = new Spell(0, GeneralSN.Hide, "Hide", "Hide"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Peek] == null) { Spell spell = new Spell(0, GeneralSN.Peek, "Peek", "Peek"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Locksmithy] == null) { Spell spell = new Spell(0, GeneralSN.Locksmithy, "Lock", "Lock"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Sneaking] == null) { Spell spell = new Spell(0, GeneralSN.Sneaking, "Sneak", "Sneak"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Steal] == null) { Spell spell = new Spell(0, GeneralSN.Steal, "Steal", "Steal"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Bash] == null) { Spell spell = new Spell(0, GeneralSN.Bash, "Bash", "Bash"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Tracking] == null) { Spell spell = new Spell(0, GeneralSN.Tracking, "Track", "Track"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Disarm] == null) { Spell spell = new Spell(0, GeneralSN.Disarm, "Disarm", "Disarm"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.EnhancedDamage] == null) { Spell spell = new Spell(0, GeneralSN.EnhancedDamage, "Enhanced Damage", "Enhanced Damage"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Kick] == null) { Spell spell = new Spell(0, GeneralSN.Kick, "Kick", "Kick"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Parry] == null) { Spell spell = new Spell(0, GeneralSN.Parry, "Parry", "Parry"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.ShieldBlock] == null) { Spell spell = new Spell(0, GeneralSN.ShieldBlock, "Shield Block", "Shield Block"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Rescue] == null) { Spell spell = new Spell(0, GeneralSN.Rescue, "Rescue", "Rescue"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.SecondAttack] == null) { Spell spell = new Spell(0, GeneralSN.SecondAttack, "Second Attack", "Second Attack"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.ThirdAttack] == null) { Spell spell = new Spell(0, GeneralSN.ThirdAttack, "Third Attack", "Third Attack"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.DualWield] == null) { Spell spell = new Spell(0, GeneralSN.DualWield, "Dual Wield", "Dual Wield"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.PiercingWeapons] == null) { Spell spell = new Spell(0, GeneralSN.PiercingWeapons, "Piercing Weapons", "Piercing Weapons"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.SlashingWeapons] == null) { Spell spell = new Spell(0, GeneralSN.SlashingWeapons, "Slashing Weapons", "Slashing Weapons"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.ConcussionWeapons] == null) { Spell spell = new Spell(0, GeneralSN.ConcussionWeapons, "Concussion Weapons", "Concussion Weapons"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.WhippingWeapons] == null) { Spell spell = new Spell(0, GeneralSN.WhippingWeapons, "Whipping Weapons", "Whipping Weapons"); spell.AddNewSpell(); }
            if (htSpellListByGSN[(int)GeneralSN.Searching] == null) { Spell spell = new Spell(0, GeneralSN.Searching, "Search", "Search"); spell.AddNewSpell(); }
        }

        public void read_sh_score()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\sh_score.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading sh_score.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            StringBuilder sb = new StringBuilder(4096);
            string szLine = sr.ReadLine();
            while (szLine.Trim() != "~" && sr.EndOfStream == false)
            {
                sb.AppendLine(szLine);
                szLine = sr.ReadLine();
            }

            sr.Close();

            sh_score_template = sb.ToString();
        }

        public void read_score()
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(EmlenMud.HostPathnameToMudDirectory + "\\" + MiscConstants.DataFileDirectory + "\\score.dat", FileMode.Open, FileAccess.Read);
            }
            catch (IOException ex) { EmlenMud.LogError("Error reading score.dat: ", ex, LogType.Always); return; }

            StreamReader sr = new StreamReader(fs);
            StringBuilder sb = new StringBuilder(4096);
            string szLine = sr.ReadLine();
            while (szLine != "~" && sr.EndOfStream == false)
            {
                sb.AppendLine(szLine);
                szLine = sr.ReadLine();
            }

            sr.Close();

            score_template = sb.ToString();
        }
    }

    public class DynamicWorldData : IDynamicWorldData
    {

        public DynamicWorldData()
        {
#if NO_SILVERLIGHT
            rgDescriptors = ArrayList.Synchronized(rgDescriptrs);
#endif
            currentTime = new TimeInfoData();
            lastCombatRound = new TimeInfoData();
            bootupTime = new TimeInfoData();
            currentTime.SetTimeInfo(DateTime.Now);
            bootupTime.SetTimeInfo(DateTime.Now);
            weatherInfo = new WeatherData();
            bidData = (IArenaBidData)new ArenaBidData();
            worldStats = new WorldStats();
        }

        /// <summary>
        /// In the dynamic world, everything - a mob instance,
        /// or a mob prototype, or a character, or an object, has a unique id.
        /// </summary>
        private long maxUniqueIdentifier = 0;

        public long MaxUniqueIdentifier
        {
            get { return maxUniqueIdentifier; }
            set { maxUniqueIdentifier = value; }
        }
        public long NextUniqueIdentifier
        {
            get { return Interlocked.Increment(ref maxUniqueIdentifier); }
        }

        public long CurrentMaxIdentifier
        {
            get { return maxUniqueIdentifier; }
        }

        public void CombatTick()
        {
            StringCodeCollection stringformatter = new StringCodeCollection(ShowFlags.None);
            bool fRemoveFromList;

            for (int i = AllCharactersInCombat.Count - 1; i >= 0; i--)
            {
                fRemoveFromList = false;
                CharacterData ch = (CharacterData)AllCharactersInCombat[i];
                if (ch == null)
                {
                    AllCharactersInCombat.RemoveAt(i);
                    continue;
                }
                else if (ch.AttackingCharacter == null)
                {
                    fRemoveFromList = true;
                }
                // Perform attacks first
                else if (!ch.CanAttackChar(ch.AttackingCharacter))
                {
                    ch.send_to_char(ch.ReasonCantAttackChar(ch.AttackingCharacter));
                    fRemoveFromList = true;
                }
                else
                {
                    // Do the actual hit
                    if (EmlenMud.PerformCombatRound(ch, ch.AttackingCharacter) == false)
                    {
                        fRemoveFromList = true;
                    }
                    else if (ch.AttackingCharacter.AttackingCharacter == null)
                    {
                        CharacterData chTarget = (CharacterData)ch.AttackingCharacter;
                        // Try to hit back... darnit!
                        // it sucks if you are getting attacked but can't hit back... but
                        // it can happen if you can't see the char or if they are wizinvis/etc
                        if (chTarget.CanAttackChar(ch) == true)
                        {
                            // pretty display message?
                            StringBuilder sb = new StringBuilder(256);
                            sb.Append("You ");
                            if (chTarget.position != CharPosition.standing && chTarget.position != CharPosition.fighting)
                            {
                                if ((int)chTarget.position <= (int)CharPosition.stunned)
                                {
#if NO_SILVERLIGHT
                                    chTarget.send_to_char("are unable to retaliate... you are " + Enum.Format(typeof(CharPosition), chTarget.position, "G") + ".");
#else
                                    chTarget.send_to_char("are unable to retaliate... you are " + ((CharPosition)chTarget.position).ToString() + ".");
#endif
                                }
                                else
                                {
                                    if (chTarget.position == CharPosition.resting ||
                                    chTarget.position == CharPosition.sleeping ||
                                    chTarget.position == CharPosition.meditating)
                                        sb.Append("leap to your feet and ");
                                    else sb.Append("take a fighting stance and ");
                                    chTarget.position = CharPosition.standing;
                                }
                            }
                            sb.Append("begin attacking ");
                            sb.Append(EmlenMud.ShortName(chTarget, ch));
                            sb.Append("!");
                            chTarget.send_to_char(sb.ToString());
                            chTarget.AttackingCharacter = ch;
                        }
                    }

                    // Then assisters join in...
                    if (!fRemoveFromList)
                    {
                        List<CharacterData> rgAssisters = ch.GetAssisters(EmlenMud.GetInRoom(ch));
                        for (int j = 0; j < rgAssisters.Count; j++)
                        {
                            CharacterData chAssister = (CharacterData)rgAssisters[j];
                            // display a pretty message... X assists Y in combat!
                            stringformatter.DisplayCodedStringTo(
                              DisplaysTo.BystandersInCharRoom | DisplaysTo.Target | DisplaysTo.chInitiated,
                              "|CName assist(s) |3Name and begin(s) attacking |TName!",
                              chAssister, ch.AttackingCharacter, ch,
                              null, "someone", "someone");

                            chAssister.AttackingCharacter = ch.AttackingCharacter;
                        }
                    }
                }

                if (fRemoveFromList)
                {
                    if ((int)ch.position >= (int)CharPosition.incapacitated)
                    {
                        ch.position = CharPosition.standing;
                    }
                    AllCharactersInCombatByUniqueID.Remove(ch.AssociatedID);
                    AllCharactersInCombat.RemoveAt(i);
                }
            }
        }

        private List<CharacterData> AllCharactersInCombat = new List<CharacterData>(128);

        public List<CharacterData> AllCharactersInCombat1
        {
            get { return AllCharactersInCombat; }
            set { AllCharactersInCombat = value; }
        }
        private ThreadSafeLookup<long, CharacterData> AllCharactersInCombatByUniqueID = new ThreadSafeLookup<long, CharacterData>();

        public ThreadSafeLookup<long, CharacterData> AllCharactersInCombatByUniqueID1
        {
            get { return AllCharactersInCombatByUniqueID; }
            set { AllCharactersInCombatByUniqueID = value; }
        }

        // Actual Mobs and Characers
        // Lists of all Characters, hashed by name
        private List<CharacterData> AllPlayers = new List<CharacterData>(64);

        public List<CharacterData> AllPlayers1
        {
            get { return AllPlayers; }
            set { AllPlayers = value; }
        }

        private ThreadSafeLookup<string, List<CharacterData>> AllChars = new ThreadSafeLookup<string, List<CharacterData>>();

        public ThreadSafeLookup<string, List<CharacterData>> AllChars1
        {
            get { return AllChars; }
            set { AllChars = value; }
        }
        private ThreadSafeLookup<int, List<CharacterData>> AllCharsByFirstTwoLetters = new ThreadSafeLookup<int, List<CharacterData>>();

        public ThreadSafeLookup<int, List<CharacterData>> AllCharsByFirstTwoLetters1
        {
            get { return AllCharsByFirstTwoLetters; }
            set { AllCharsByFirstTwoLetters = value; }
        }

        private IWorldStats worldStats;

        public IWorldStats WorldStats
        {
            get { return worldStats; }
            set { worldStats = value; }
        }

#if NO_SILVERLIGHT
        // Conections to the server
        private ArrayList rgDescriptrs = new ArrayList(32);

        public ArrayList RgDescriptrs
        {
            get { return rgDescriptrs; }
            set { rgDescriptrs = value; }
        }
        private ArrayList rgDescriptors;

        public ArrayList RgDescriptors
        {
            get { return rgDescriptors; }
            set { rgDescriptors = value; }
        }
#endif

        // Intra-MUD communication
        //public TcpClient[] outgoing = new TcpClient[5];
        //public string[] connection_names = new string[5];

        // Aggressive creatures
        private List<CharacterData> aggressiveMobs = new List<CharacterData>();

        public List<CharacterData> AggressiveMobs
        {
            get { return aggressiveMobs; }
            set { aggressiveMobs = value; }
        }

        // Actual object instances
        private List<ObjectData> AllObjects = new List<ObjectData>(1024);

        public List<ObjectData> AllObjects1
        {
            get { return AllObjects; }
            set { AllObjects = value; }
        }
        // An Hashtable of ArrayLists
        private ThreadSafeLookup<int, List<ObjectData>> ObjectsByProtoVnum = new ThreadSafeLookup<int, List<ObjectData>>();

        public ThreadSafeLookup<int, List<ObjectData>> ObjectsByProtoVnum1
        {
            get { return ObjectsByProtoVnum; }
            set { ObjectsByProtoVnum = value; }
        }

        // Date/time/weather
        private TimeInfoData lastCombatRound;

        public TimeInfoData LastCombatRound
        {
            get { return lastCombatRound; }
            set { lastCombatRound = value; }
        }
        private TimeInfoData currentTime;

        public TimeInfoData CurrentTime
        {
            get { return currentTime; }
            set { currentTime = value; }
        }
        private TimeInfoData bootupTime;

        public TimeInfoData BootupTime
        {
            get { return bootupTime; }
            set { bootupTime = value; }
        }
        private WeatherData weatherInfo;

        public WeatherData WeatherInfo
        {
            get { return weatherInfo; }
            set { weatherInfo = value; }
        }
        private IArenaBidData bidData;

        public IArenaBidData BidData
        {
            get { return bidData; }
            set { bidData = value; }
        }

        // NYI - open to builders only
        private bool isBuilderPort;

        public bool IsBuilderPort
        {
            get { return isBuilderPort; }
            set { isBuilderPort = value; }
        }
        private int ticksToReboot;

        public int TicksToReboot
        {
            get { return ticksToReboot; }
            set { ticksToReboot = value; }
        }

        public void reset_world()
        {
            foreach (RoomData room in EmlenMud.WorldTemplates.htRooms.Values)
            {
                EmlenMud.DoReset(room);
            }
        }

        public void LinkAllRoomsByExits()
        {
            ExitData pexit;
            int door;

            foreach (RoomData oneroom in EmlenMud.WorldTemplates.htRooms.Values)
            {
                for (door = 0; door < (int)GeneralDirection.Max; door++)
                {
                    pexit = oneroom[(GeneralDirection)door];
                    if (pexit != null)
                    {
                        if (pexit.Vnum > 1200000 || pexit.Vnum == 0)
                            continue;
                        if (EmlenMud.WorldTemplates.htRooms.ContainsKey(pexit.Vnum) == true)
                        {
                            pexit.to_room = EmlenMud.WorldTemplates.htRooms[pexit.Vnum];
                        }
                    }
                }
            }
        }
    }

    public class WorldStats : IWorldStats
    {

        public WorldStats() { }
        private int mobcount = 0;

        public int Mobcount
        {
            get { return mobcount; }
            set { mobcount = value; }
        }
        private ThreadSafeLookupNonRef<long, int> mobinstancecount = new ThreadSafeLookupNonRef<long, int>();		/* How many mobs are there of this type? */

        public ThreadSafeLookupNonRef<long, int> Mobinstancecount
        {
            get { return mobinstancecount; }
            set { mobinstancecount = value; }
        }
        private ThreadSafeLookupNonRef<long, int> killedcount = new ThreadSafeLookupNonRef<long, int>();		/* How many times has this mob been killed since reboot? */

        public ThreadSafeLookupNonRef<long, int> Killedcount
        {
            get { return killedcount; }
            set { killedcount = value; }
        }
    }

    public class Command : ICommand
    {
        public Command(string commandstringIn, CommandDelegate commandfunctionIn,
          CharPosition positionIn, int levelIn,
          LogType logtypeIn, string descrIn, string presetFirstArgumentIn, int isShortCut)
        {
            commandstring = commandstringIn;
            commandfunction = commandfunctionIn;
            position = positionIn;
            level = levelIn;
            logtype = logtypeIn;
            descr = descrIn;
            presetFirstArgument = presetFirstArgumentIn;
            nShortcut = isShortCut;
        }

        private string presetFirstArgument = "";

        public string PresetFirstArgument
        {
            get { return presetFirstArgument; }
            set { presetFirstArgument = value; }
        }
        private string commandstring = "";

        public string Commandstring
        {
            get { return commandstring; }
            set { commandstring = value; }
        }
        private CommandDelegate commandfunction = null;

        public CommandDelegate Commandfunction
        {
            get { return commandfunction; }
            set { commandfunction = value; }
        }
        private CharPosition position = CharPosition.dead;

        public CharPosition Position
        {
            get { return position; }
            set { position = value; }
        }
        private int level = -1;

        public int Level
        {
            get { return level; }
            set { level = value; }
        }
        private LogType logtype = LogType.Normal;

        public LogType Logtype
        {
            get { return logtype; }
            set { logtype = value; }
        }
        private string descr = "";

        public string Descr
        {
            get { return descr; }
            set { descr = value; }
        }
        private int nShortcut = 0;

        public int NShortcut
        {
            get { return nShortcut; }
            set { nShortcut = value; }
        }

        /// <summary>
        /// This guarantees the argument is not null (at minimum, if it is not specified
        /// the default is the string specified by presetFirstArgument.
        /// All commands can be certain that the character is non-null
        /// if they go through PerformCommand or RawPerformCommand
        /// </summary>
        /// <param name="performingCharacter"></param>
        /// <param name="presetFirstArgument"></param>
        /// <param name="szUserArguments"></param>
        /// <returns></returns>
        private string RawPerformCommand(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments == null) szUserArguments = presetFirstArgument;
            else
            {
                int nFirst = szUserArguments.IndexOf(" ", 0, szUserArguments.Length, StringComparison.Ordinal);
                if (nFirst <= 0 || nFirst == szUserArguments.Length - 1) szUserArguments = presetFirstArgument;
                else szUserArguments = szUserArguments.Substring(nFirst + 1).Trim();
            }

            return commandfunction(ch, presetFirstArgument, szUserArguments);
        }

        public string PerformCommand(CharacterData ch, string presetFirstArgument, string szUserArguments, int nOverrideLevel, CharPosition positionOverride)
        {
            if (ch == null) return "No character to perform command";
            return RawPerformCommand(ch, presetFirstArgument, szUserArguments);
        }

        public string PerformCommand(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (ch == null) return "No character to perform command";
            if (ch.Level < level) return null;
            if ((int)ch.position < (int)position)
            {
                return "You are currently " +
                  Enum.GetName(typeof(CharPosition), ch.position) +
                  ".  You must be at least " +
                  Enum.GetName(typeof(CharPosition), position) +
                  " to do that.";
            }

            return RawPerformCommand(ch, presetFirstArgument, szUserArguments);
        }

    }


    // OLD CODE to PORT

    //void
    //do_memory (CharacterData  chr, string szUserArguments)
    //{
    //  SINGLE_OBJECT *oo;
    //  CharacterData md;
    //  REALCharacterData pcd;
    //  int aglist;
    //  int flist;
    //  AFFECT_DATA *aff;
    //  OBJ_PROTOTYPE *oid;
    //  PROTOTYPE *mid;
    //  EXIT_DATA *exd;
    //  AREA_DATA *ar;
    //  RESET_DATA *rsd;
    //  ROOM_DATA *rrr;
    //  SHOP_DATA *shd;
    //  CED_DATA *ced;
    //  int socnum = 0;
    //  TEMP_STR *tstr;
    //  SOCIAL *s;
    //  int ctobj;
    //  int ctmob;
    //  int frmob;
    //  int frobj;
    //  long estimate=0;
    //  int fields=0;
    //  int ffields=0;
    //  COMBAT_FIELD *f;
    //  FGT *ff;
    //  char general_use[STD_LENGTH];
    //  long workspace;
    //  DEFINE_COMMAND ("memory", do_memory, POSITION_DEAD, 100, NORMAL, "Shows memory info, structure sizes, and bandwidth use.")

    //    ctobj = 0;
    //  ctmob = 0;
    //  frmob = 0;
    //  frobj = 0;
    //  aglist = 0;
    //  flist = 0;
    //  if (!str_cmp(szUserArguments,"timing")) {
    //   sprintf(general_use, "Total cpu time from bootup: %.2f seconds.\n\r", ((double) mytime()/1000000)); 
    //   send_to_char(general_use,chr);
    //   sprintf(general_use, "Commands: %.2f seconds,  Average: %ld microseconds\n\r", ((double) total_time[InterprettedCommands]/1000000), total_time[InterprettedCommands]/times_through[InterprettedCommands]);
    //   send_to_char(general_use,chr);
    //   sprintf(general_use, "Update Loop: %.2f seconds,  Average: %ld microseconds\n\r", ((double) total_time[CurrentMaxUpdate]/1000000), total_time[CurrentMaxUpdate]/times_through[CurrentMaxUpdate]);
    //   send_to_char(general_use,chr);
    ///*	sprintf(general_use, "Shared mem size: %ld, Unshared data size: %ld, Unshared stack size: %ld.\n\r",
    //      info_mem(1),info_mem(2),info_mem(3));
    //   send_to_char(general_use,chr);*/
    //   return;
    //   }
    //  for (f=field_list; f; f=f->next) fields++;
    //  for (f=free_field_list; f; f=f->next) ffields++;
    //  for (s = social_list; s != NULL; s = s->next)
    //    socnum++;
    //  for (md = aggressiveMobs; md != NULL; md = md->gen_next)
    //    aglist++;
    //  for (md = f_first; md != NULL; md = md->next_fighting)
    //    {
    //      flist++;
    //    }
    //  for (oo = object_list; oo != NULL; oo = oo->next)
    //    ctobj++;
    //  for (md = char_list; md != NULL; md = md->next)
    //    ctmob++;

    //  if (((long) currentTime - (long) bt_tm) / 10 != 0)
    //    workspace = (((meg_sent * 104857) + (chars_sent / 10)) / (((long) currentTime - (long) bt_tm) / 10));
    //  else
    //    workspace = 1024;
    //  sprintf (general_use, "Fields  %-5d [%5db]\t\t\t", fields, sizeof(*f));
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "FFields %-5d\n\r", ffields);
    //  send_to_char (general_use, chr);
    //  estimate+=(fields*sizeof(*f)) + (ffields*sizeof(*f));
    //  sprintf (general_use, "Affects %-5d [%5db]\t\t\t", top_affect, sizeof (*aff));
    //  send_to_char (general_use, chr);
    //  estimate+=top_affect*sizeof(*aff);
    //  sprintf (general_use, "Areas   %-5d [%5db]\n\r", top_area, sizeof (*ar));
    //  send_to_char (general_use, chr);
    //  estimate+=top_area*sizeof(*ar);
    //  sprintf (general_use, "Exits   %-5d [%5db]\t\t\t", top_exit, sizeof (*exd));
    //  send_to_char (general_use, chr);
    //  estimate+=top_exit*sizeof(*exd);
    //  sprintf (general_use, "MobInd  %-5d [%5db]\n\r", top_mob_index, sizeof (*mid));
    //  send_to_char (general_use, chr);
    //  estimate+=top_mob_index*sizeof(*mid);
    //  sprintf (general_use, "Mobs/Ch %-5d [%5db]\t\t\t", ctmob, sizeof (*md));
    //  send_to_char (general_use, chr);
    //  estimate+=ctmob*sizeof(*md);
    //  sprintf (general_use, "TempStr %-5d [%5db]\n\r", top_temp, sizeof (*tstr));
    //  send_to_char (general_use, chr);
    //  estimate+=top_temp*sizeof(*tstr);
    //  sprintf (general_use, "ObjInd  %-5d [%5db]\t\t\t", top_obj_index, sizeof (*oid));
    //  send_to_char (general_use, chr);
    //  estimate+=top_obj_index*sizeof(*oid);
    //  sprintf (general_use, "ObjsNow %-5d [%5db]\n\r", ctobj, sizeof (*oo));
    //  send_to_char (general_use, chr);
    //  estimate+=ctobj*sizeof(*oo);
    //  sprintf (general_use, "Resets  %-5d [%5db]\t\t\t", top_reset, sizeof (*rsd));
    //  send_to_char (general_use, chr);
    //  estimate+=top_reset*sizeof(*rsd);
    //  sprintf (general_use, "Rooms   %-5d [%5db]\n\r", top_room, sizeof (*rrr));
    //  send_to_char (general_use, chr);
    //  estimate+=top_room*sizeof(*rrr);
    //  sprintf (general_use, "Shops   %-5d [%5db]\t\t\t", top_shop, sizeof (*shd));
    //  send_to_char (general_use, chr);
    //  estimate+=top_shop*sizeof(*shd);
    //  sprintf (general_use, "Ced's   %-5d [%5db]\n\r", top_ced, sizeof (*ced));
    //  send_to_char (general_use, chr);
    //  estimate+=top_ced*sizeof(*ced);
    //  sprintf (general_use, "Plyrsiz %-5d [%5db]\t\t\t", max_connected, sizeof (*pcd));
    //  send_to_char (general_use, chr);
    //  estimate+=max_connected*(sizeof(*pcd)+512);
    //  sprintf (general_use, "FGTstrc %-5d [%5db]\n\r", total_fgt,sizeof(*ff));
    //  send_to_char (general_use, chr);
    //  estimate+=total_fgt*sizeof(*ff);
    //  sprintf (general_use, "\n\rSocials %-5d\t\t", socnum);
    //  send_to_char (general_use, chr);
    //  estimate+=socnum*128;
    //  sprintf (general_use, "Descrps %-5d\t\t", ndescrooms);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "ObjFree %-5d\n\r", frobj);
    //  send_to_char (general_use, chr);
    //  estimate+=frobj*sizeof(*oo);
    //  sprintf (general_use, "AggSize %-5d\t\t", aglist);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "FightLs %-5d\n\r", flist);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "MobFree %-5d\t\t", frmob);
    //  send_to_char (general_use, chr);
    //  estimate+=frmob*sizeof(*md);
    //  sprintf (general_use, "ExDes   %-5d\t\t", top_ed);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "Helps   %-5d\n\r", top_help);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "\n\rTop Vnums: %d mobs  %d objs  %d rooms\n\r", top_vnum_mob,
    //      top_vnum_obj,
    //      top_vnum_room);
    //  send_to_char (general_use, chr);

    //  sprintf (general_use, "%d shared-string bytes used.\n\r",
    //      sAllocString + 10);
    //  send_to_char (general_use, chr);
    //  estimate+=sAllocString+1024;
    //  sprintf (general_use, "Average chars/sec (bandwidth): %-5ld\n\r", workspace);
    //  send_to_char (general_use, chr);
    ///*  sprintf (general_use, "Sent %d Meg %ld Chrs\n\r\n\r", meg_sent, chars_sent);
    //  send_to_char (general_use, chr);*/
    //  sprintf(general_use, "Estimated Data Memory Usage: %ld (%ldK).\n\r",estimate,estimate/1024);
    //  send_to_char (general_use, chr);

    ///*
    //   sprintf( general_use, "Perms   %5d blocks  of %7d bytes.\n\r",
    //   nAllocPerm, sAllocPerm );
    //   send_to_char( general_use, chr ); */

    //  return;
    //}


    //void
    //do_world (CharacterData  chr, string szUserArguments)
    //{
    //  int days;
    //  int hours;
    //  int minutes;
    //  long seconds;
    //  char general_use[STD_LENGTH];
    //  DEFINE_COMMAND ("world", do_world, POSITION_DEAD, 0, NORMAL, "Shows statistics about uptime and areas/rooms.")

    //    send_to_char ("---------- [A Few Mud Statistics] ----------\n\r\n\r", chr);
    //  sprintf (general_use, "Areas explorable (OpenToPlayers)             [\x1B[34;1m%5d\x1B[37;0m]\n\r", num_areas);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "Rooms explorable (Accessable)       [\x1B[34;1m%5d\x1B[37;0m]\n\r", num_rooms);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "Max # of players on since reboot    [\x1B[34;1m%5d\x1B[37;0m]\n\r", max_connected);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "\n\rReason for last mud termination: \x1B[37;1m%s\x1B[0m\n\r", reasonone);
    //  send_to_char (general_use, chr);
    //  sprintf (general_use, "Current System Time Now: %s\r", ((string ) ctime (&currentTime)));
    //  send_to_char (general_use, chr);
    //  seconds = currentTime - bt_tm;
    //  minutes = seconds / 60;
    //  seconds %= 60;
    //  hours = minutes / 60;
    //  minutes %= 60;
    //  days = hours / 24;
    //  hours %= 24;
    //  sprintf (general_use, "Current Uptime: %d day%s, %d hour%s, %d minute%s, %ld second%s\n\r",
    //      days, ((days == 0 || days > 1) ? "s" : ""),
    //      hours, ((hours == 0 || hours > 1) ? "s" : ""),
    //      minutes, ((minutes == 0 || minutes > 1) ? "s" : ""),
    //      seconds, ((seconds == 0 || seconds > 1) ? "s" : ""));
    //  send_to_char (general_use, chr);
    //  return;
    //}


    // MORE (crap) OLD CODE to PORT (or perhaps not)

    //void
    //bug (const string str, int param)
    //{
    //  char general_use[STD_LENGTH];
    //  FILE *fp;

    //  if (fpArea != NULL)
    //    {
    //      int iLine;
    //      int iChar;

    //      if (fpArea == stdin)
    //   {
    //     iLine = 0;
    //   }
    //      else
    //   {
    //     iChar = ftell (fpArea);
    //     fseek (fpArea, 0, 0);
    //     for (iLine = 0; ftell (fpArea) < iChar; iLine++)
    //       {
    //         while (getc (fpArea) != '\n')
    //      ;
    //       }
    //     fseek (fpArea, iChar, 0);
    //   }

    //      sprintf (general_use, "[<FBUG>] FILE: %s LINE: %d", strArea, iLine);
    //      log_string (general_use);

    //      sprintf (log_buf, "Notify> %s", general_use);
    //      do_global (log_buf, LEVEL_PLAYER_IMMORTAL, WIZ_NOTIFY_BUG);

    //      if ((fp = fopen ("shutdown.txt", "a")) != NULL)
    //   {
    //     fprintf (fp, "[--!!--] %s\n", general_use);
    //     fclose (fp);
    //   }
    //    }

    //  strcpy (general_use, "[*BUG*] ");
    //#ifdef WIN32 
    //  sprintf(general_use + strlen (general_use), str, param);
    //#else
    //  sprintf (general_use + strlen (general_use), str, param);
    //#endif
    //  log_string (general_use);

    //  return;
    //}



    //void
    //log_string (const string str)
    //{
    //  string strtime;
    //  char genn[700];
    //  /* can't log me */
    //  if (!str_prefix ("Log Orin", str))
    //    return;
    //  if (!str_prefix ("Orin", str))
    //    return;
    //  strtime = ctime (&currentTime);
    //  strtime[strlen (strtime) - 1] = '\0';
    //  fprintf (stderr, "[%s] %s\n", strtime, str);

    //  sprintf (genn, "GodInfo> %s", str);
    //  NOTIFY (genn, LEVEL, WIZ_NOTIFY_LOG);
    //  LEVEL = LEVEL_PLAYER_IMMORTAL;

    //  return;
    //}

    [Serializable]
    public class ArenaBidData : IArenaBidData
    {

        public ArenaBidData() { }
        private string[] fighters = new string[2];	/*[0] and [1] hold the two fighters' names */

        public string[] Fighters
        {
            get { return fighters; }
            set { fighters = value; }
        }
        private List<string> bidders = new List<string>(2);	/*Character names of bidders (didn't to structs cuz of quitting/etc */

        public List<string> Bidders
        {
            get { return bidders; }
            set { bidders = value; }
        }
        private ThreadSafeLookupNonRef<long, int> bids = new ThreadSafeLookupNonRef<long, int>();		/*actually monetary bid */

        public ThreadSafeLookupNonRef<long, int> Bids
        {
            get { return bids; }
            set { bids = value; }
        }
        private ThreadSafeLookupNonRef<long, int> bidfor = new ThreadSafeLookupNonRef<long, int>();		/*FALSE for fighter 0, TRUE for fighter 1 */

        public ThreadSafeLookupNonRef<long, int> Bidfor
        {
            get { return bidfor; }
            set { bidfor = value; }
        }
        private bool taking_bids = false;		/*Are we still up for bidding or has the fight begun? */

        public bool Taking_bids
        {
            get { return taking_bids; }
            set { taking_bids = value; }
        }
        private int waitticks = 0;

        public int Waitticks
        {
            get { return waitticks; }
            set { waitticks = value; }
        }
    }


    public class MudCommands
    {
        public static void RegisterAllCommands()
        {
            Command cmd;
            cmd = new Command("Show_Questflags", Cmds.show_questflags, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Normal, "Shows questflags on a given player.", "all", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Unlearn", Cmds.do_unlearn, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Always, "Allows you to unlearn a specific spell or skill.", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Testing", Cmds.do_test_command, CharPosition.dead, 0, LogType.Normal, "Testing out commands and command registration.", "test", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Look", Cmds.do_look, CharPosition.resting, 0, LogType.Normal, "Look in a room, in an object, at a character, at an object, etc.", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("L", Cmds.do_look, CharPosition.resting, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Lo", Cmds.do_look, CharPosition.resting, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Quit", Cmds.do_quit, CharPosition.dead, 0, LogType.Normal, "Quit the game (for now)...", "now", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Say", Cmds.do_say, CharPosition.incapacitated, 0, LogType.Normal, "Say something to all others in the room.", "room", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Sa", Cmds.do_say, CharPosition.incapacitated, 0, LogType.Normal, "", "room", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Sya", Cmds.do_say, CharPosition.incapacitated, 0, LogType.Normal, "", "room", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Tell", Cmds.do_tell, CharPosition.incapacitated, 0, LogType.Normal, "Tell something to someone in specific", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Te", Cmds.do_tell, CharPosition.incapacitated, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Tlel", Cmds.do_tell, CharPosition.incapacitated, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("T", Cmds.do_tell, CharPosition.incapacitated, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("N", Cmds.do_north, CharPosition.standing, 0, LogType.Normal, "Move north", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("S", Cmds.do_south, CharPosition.standing, 0, LogType.Normal, "Move south", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("E", Cmds.do_east, CharPosition.standing, 0, LogType.Normal, "Move east", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("W", Cmds.do_west, CharPosition.standing, 0, LogType.Normal, "Move west", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("U", Cmds.do_up, CharPosition.standing, 0, LogType.Normal, "Move up", "", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("D", Cmds.do_down, CharPosition.standing, 0, LogType.Normal, "Move down", "", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("North", Cmds.do_north, CharPosition.standing, 0, LogType.Normal, "Move north", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("South", Cmds.do_south, CharPosition.standing, 0, LogType.Normal, "Move south", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("East", Cmds.do_east, CharPosition.standing, 0, LogType.Normal, "Move east", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("West", Cmds.do_west, CharPosition.standing, 0, LogType.Normal, "Move west", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Up", Cmds.do_up, CharPosition.standing, 0, LogType.Normal, "Move up", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Down", Cmds.do_down, CharPosition.standing, 0, LogType.Normal, "Move down", "", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Help", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "Get help on a topic", "all", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Hlp", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "", "all", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Hlep", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "", "all", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Commands", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "Show all commands", "allcommands", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Cmd", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "", "allcommands", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Cmds", Cmds.do_help, CharPosition.dead, 0, LogType.Normal, "", "allcommands", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Autoexit", Cmds.do_autoexit, CharPosition.dead, 0, LogType.Normal, "Turn autoexit on or off", "toggle", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("AutoE", Cmds.do_autoexit, CharPosition.dead, 0, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("AutoEx", Cmds.do_autoexit, CharPosition.dead, 0, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("AutoX", Cmds.do_autoexit, CharPosition.dead, 0, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Fly", Cmds.do_fly, CharPosition.fighting, 0, LogType.Normal, "Begin flying", "on", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Land", Cmds.do_land, CharPosition.fighting, 0, LogType.Normal, "Land (if you are flying)", "off", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Lnad", Cmds.do_land, CharPosition.fighting, 0, LogType.Normal, "", "off", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Who", Cmds.do_who, CharPosition.dead, 0, LogType.Normal, "List who is in the game", "players", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("ListSocials", Cmds.do_socials, CharPosition.dead, 0, LogType.Normal, "List all available socials", "all", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Socials", Cmds.do_socials, CharPosition.dead, 0, LogType.Normal, "List all available socials", "all", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Soc", Cmds.do_socials, CharPosition.dead, 0, LogType.Normal, "", "all", 1);
            EmlenMud.AddCommand(cmd);

            //cmd = new Command("ShowAllCharacters", Cmds.do_list_all_chars, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Always, "Lists every character instance in the game - careful!");
            //EmlenMud.AddCommand(cmd);

            cmd = new Command("ShowCharactersInArea", Cmds.do_who_area, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Always, "Lists all characters in the current area (will take an areaname argument in the future)", "current", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("ShowCharsInArea", Cmds.do_who_area, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Always, "Lists all characters in the current area (will take an areaname argument in the future)", "current", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("ListEnums", Cmds.do_list_typeInfo, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Normal, "List or get details about enumerations and flags used internally by the game engine", "enums", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("ListInternalClasses", Cmds.do_list_typeInfo, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Normal, "List or get details about classes used internally by the game engine", "classes", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Holywalk", Cmds.do_holywalk, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "Move across all terrain types, don't leave any tracks, move through doors, etc", "toggle", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("HWalk", Cmds.do_holywalk, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Holylight", Cmds.do_holylight, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "See all characters, in the dark, etc, regardless of status. However, higher level immortals will remain invisible if they have WizInvis set above your current level.", "toggle", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("HLight", Cmds.do_holylight, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Holypeace", Cmds.do_holypeace, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "Stop all fights and do not allow fighting in the current room.", "toggle", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("HPeace", Cmds.do_holypeace, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Peace", Cmds.do_holypeace, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "Stop all fights and do not allow fighting in the current room.", "on", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Wizinvis", Cmds.do_wizinvis, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "Wininvis makes you invisible to everyone, except for similar and higher level immortals that have holylight on.", "0", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("WInvis", Cmds.do_wizinvis, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "", "0", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Announce", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Announce lets you communicate with every player in the game", "0|{Y}|{Y}|{Y}|, |announce", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Ann", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "", "0|{Y}|{Y}|{Y}|, |announce", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Thunder", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Thunder lets you thunder a message to every player in the game", "0|{Y}|{B}|{C}|, |thunder", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Thund", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "", "0|{Y}|{B}|{C}|, |thunder", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Broadcast", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Broadcast lets you broadcast important messages to every player in the game", "0|{Y}|{Y}|{G}|: |broadcast", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("BCast", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "", "0|{Y}|{Y}|{G}|: |broadcast", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Godtalk", Cmds.do_announce_to_only_those_who_can_see, CharPosition.dead, MiscConstants.LEVEL_MAXIMUM, LogType.Normal, "Godtalk lets you speak to all other Level 110 players", "110|{G}|{C}|{G}|: |communicate", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("[", Cmds.do_announce_to_only_those_who_can_see, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "", "110|{G}|{C}|{G}|: |communicate", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Immtalk", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "Immtalk lets you speak to all other immortals, regardless of whether or not they can see you", "100|{Y}|{G}|{C}|: |communicate", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("]", Cmds.do_announce_use_someone_text, CharPosition.dead, MiscConstants.LEVEL_PLAYER_IMMORTAL, LogType.Normal, "", "100|{Y}|{G}|{C}|: |communicate", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Attack", Cmds.do_attack, CharPosition.fighting, 0, LogType.Normal, "Attack a character or player", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Att", Cmds.do_attack, CharPosition.fighting, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Kill", Cmds.do_attack, CharPosition.fighting, 0, LogType.Normal, "Attack a character or player", "", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("K", Cmds.do_attack, CharPosition.fighting, 0, LogType.Normal, "", "", 1);
            EmlenMud.AddCommand(cmd);

            //cmd = new Command("Flee", Cmds.do_flee, CharPosition.fighting, 0, LogType.Normal, "This command allows you to flee from combat.", "");
            //EmlenMud.AddCommand(cmd);

            cmd = new Command("Follow", Cmds.do_follow, CharPosition.standing, 0, LogType.Normal, "Begin or stop following a character or player - NOT YET WORKING", "self", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Fol", Cmds.do_follow, CharPosition.standing, 0, LogType.Normal, "", "self", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("AutoAssist", Cmds.do_autoassist, CharPosition.standing, 0, LogType.Normal, "Toggle assisting a character or player in combat if they attack (or are attacked) NOT YET WORKING", "self", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("AutoA", Cmds.do_autoassist, CharPosition.standing, 0, LogType.Normal, "", "self", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("ViewArea", Cmds.view_area, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Writes out the current area to your client for browsing (no arguments allowed yet)", "", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Setting", Cmds.do_settings, CharPosition.dead, 0, LogType.Normal, "View or modify your general player settings", "toggle", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("Set", Cmds.do_settings, CharPosition.dead, 0, LogType.Normal, "", "toggle", 1);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Combat", Cmds.do_combat_settings, CharPosition.dead, 0, LogType.Normal, "View or modify your combat specific settings", "toggle", 0);
            EmlenMud.AddCommand(cmd);

            cmd = new Command("Goto", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Go to a room, player, object, or character in the game", "room", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("GotoRoom", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Go to a specific room VNUM", "room", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("GotoMob", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Go to a specific Mob in the game (by vnum or name)", "mob", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("GotoPlayer", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Go to a specific Player in the game (by name)", "player", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("GotoObject", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "Go to a specific Object in the game (by vnum only at the moment)", "object", 0);
            EmlenMud.AddCommand(cmd);
            cmd = new Command("GotoObj", Cmds.do_goto, CharPosition.dead, MiscConstants.LEVEL_PLAYER_BUILDER, LogType.Normal, "", "object", 0);
            EmlenMud.AddCommand(cmd);
        }

    }

    public class TrackData : ITrackData
    {

        public TrackData()
        {
            ch = null;
            dir = new GeneralDirection[(int)EnterOrLeave.CurrentMax];
            timeInfo = new TimeInfoData[(int)EnterOrLeave.CurrentMax];
            this[EnterOrLeave.enter] = GeneralDirection.Max;
            this[EnterOrLeave.leave] = GeneralDirection.Max;
        }

        public GeneralDirection this[EnterOrLeave enterOrLeave]
        {
            get { return dir[(int)enterOrLeave]; }
            set { dir[(int)enterOrLeave] = value; SetTimeTrackMade(enterOrLeave); }
        }

        public TimeInfoData GetTimeTrackMade(EnterOrLeave enterOrLeave)
        {
            return timeInfo[(int)enterOrLeave];
        }

        public void SetTimeTrackMade(EnterOrLeave enterOrLeave)
        {
            timeInfo[(int)enterOrLeave] = EmlenMud.DynamicWorld.CurrentTime;
        }

        public TimeSpan AgeOfTrack(EnterOrLeave enterOrLeave)
        {
            return timeInfo[(int)enterOrLeave].ElapsedTime;
        }

        private CharacterData ch;

        public CharacterData Ch
        {
            get { return ch; }
            set { ch = value; }
        }
        private GeneralDirection[] dir;

        public GeneralDirection[] Dir
        {
            get { return dir; }
            set { dir = value; }
        }
        private TimeInfoData[] timeInfo;

        public TimeInfoData[] TimeInfo
        {
            get { return timeInfo; }
            set { timeInfo = value; }
        }
    }

    // OLD CODE to port... TRACKING and YELLING MOBS (I think)
    //   void 
    //do_mount (CharacterData  chr, string szUserArguments)
    //{
    //  char buf[STD_LENGTH];
    //  CharacterData victim;
    //  DEFINE_COMMAND ("mount", do_mount, POSITION_STANDING, 0, NORMAL, "Allows you to mount a rideable creature or person.")

    //    one_argy (szUserArguments, buf);
    //  if (buf[0] == '\0')
    //    {
    //      send_to_char ("Mount whom?\n\r", chr);
    //      return;
    //    }
    //  if ((victim = get_char_room (chr, buf)) == NULL)
    //    {
    //      send_to_char ("They aren't here.\n\r", chr);
    //      return;
    //    }
    //  if (victim == chr)
    //    {
    //      send_to_char ("You can't mount yourself!\n\r", chr);
    //      return;
    //    }
    //  if (RIDING (chr) != NULL)
    //    {
    //      send_to_char ("Your chRiding someone else!\n\r", chr);
    //      return;
    //    }
    //  if (MOUNTED_BY (chr) != NULL)
    //    {
    //      send_to_char ("Your being ridden by someone else!\n\r", chr);
    //      return;
    //    }
    //  if (IS_SET (chr->currentlyAffectedBy, AFF_FLYING))
    //    {
    //      send_to_char ("You can't ride and fly at the same time!\n\r", chr);
    //      return;
    //    }
    //  if (IS_PLAYER (chr) &&
    //      !IS_SET (victim->currentActionsAndBehavior, ACT_MOUNTABLE) && !IS_IMMORTAL (chr))
    //    {
    //      send_to_char ("You can't ride that.\n\r", chr);
    //      return;
    //    }
    //  if (RIDING (victim) != NULL)
    //    {
    //      send_to_char ("They are chRiding someone else!\n\r", chr);
    //      return;
    //    }
    //  if (MOUNTED_BY (victim) != NULL)
    //    {
    //      send_to_char ("They are being ridden by someone else!\n\r", chr);
    //      return;
    //    }
    ///*if (victim->level>chr->level) 
    //   {
    //   send_to_char("You cannot control mounts that are a higher level than your level.\n\r",chr); 
    //   return;
    //   }
    // */
    //  check_fgt (chr);
    //  check_fgt (victim);
    //  chr->fightInfoInternal->chRiding = victim;
    //  victim->fightInfoInternal->chMountedBy = chr;
    //  currentActionsAndBehavior ("$n mounts $N, and starts chRiding $M.", chr, NULL, victim, TO_ROOM);
    //  currentActionsAndBehavior ("You mount $N, and start chRiding $M.", chr, NULL, victim, TO_CHAR);
    //  currentActionsAndBehavior ("$n mounts you.", chr, NULL, victim, TO_VICT);
    //  return;
    //}

    //void 
    //do_dismount (CharacterData  chr, string szUserArguments)
    //{
    //  DEFINE_COMMAND ("dismount", do_dismount, POSITION_RESTING, 0, NORMAL, "Allows you to dismount from a mount.")

    //    if (RIDING (chr) == NULL)
    //    {
    //      send_to_char ("You're not chRiding anything.\n\r", chr);
    //      return;
    //    }
    //  currentActionsAndBehavior ("$n dismounts from $N.", chr, NULL, RIDING (chr), TO_NOTVICT);
    //  currentActionsAndBehavior ("You dismount from $N.", chr, NULL, RIDING (chr), TO_CHAR);
    //  currentActionsAndBehavior ("$n dismounts from you.", chr, NULL, RIDING (chr), TO_VICT);
    //  check_fgt (chr);
    //  check_fgt (chr->fightInfoInternal->chRiding);
    //  chr->fightInfoInternal->chRiding->fightInfoInternal->chMountedBy = NULL;
    //  chr->fightInfoInternal->chRiding = NULL;
    //  return;
    //}

    //void 
    //do_buck (CharacterData  chr, string szUserArguments)
    //{
    //  DEFINE_COMMAND ("buck", do_buck, POSITION_RESTING, 0, NORMAL, "Bucks off your current rider.")

    //    if (MOUNTED_BY (chr) == NULL)
    //    {
    //      send_to_char ("There is no one chRiding you.\n\r", chr);
    //      return;
    //    }
    //  currentActionsAndBehavior ("$n bucks $N!", chr, NULL, MOUNTED_BY (chr), TO_NOTVICT);
    //  currentActionsAndBehavior ("You buck $M!", chr, NULL, MOUNTED_BY (chr), TO_CHAR);
    //  currentActionsAndBehavior ("$n bucks you from $m!", chr, NULL, MOUNTED_BY (chr), TO_VICT);
    //  check_fgt (chr);
    //  check_fgt (chr->fightInfoInternal->chMountedBy);
    //  chr->fightInfoInternal->chMountedBy->fightInfoInternal->chRiding = NULL;
    //  NEW_POSITION(chr->fightInfoInternal->chMountedBy, POSITION_RESTING);
    //  chr->fightInfoInternal->chMountedBy = NULL;
    //  return;
    //}

    ///* #define TRACK_THROUGH_DOORS */
    ///* track idea taken from another mud code.  Not used - we use footprints instead */
    //#define BFS_ERROR -1
    //#define BFS_ALREADY_THERE -2
    //#define BFS_NO_PATH -3
    //struct bfs_queue_struct
    //{
    //  ROOM_DATA *currentRoom;
    //  short moveDirection;
    //  short depth;
    //  struct bfs_queue_struct *next;
    //}

    // ;
    //struct room_list_struct
    //  {
    //    ROOM_DATA *currentRoom;
    //    struct room_list_struct *next;
    //  }

    // ;
    //static struct bfs_queue_struct *queue_head = NULL, *queue_tail = NULL;
    //static struct room_list_struct *list_head = NULL, *list_tail = NULL;
    ///*
    //   extern const string  dir_name [];
    // */
    ///* Utility macros */
    //#define MARK( currentRoom ) ( SET_BIT( ( currentRoom )->rmflags, R_MARK))
    //#define UNMARK( currentRoom ) ( REMOVE_BIT( ( currentRoom )->rmflags, R_MARK))
    //#define IS_MARKED( currentRoom ) ( IS_SET( ( currentRoom )->rmflags, R_MARK))
    ///*
    //   #define TOROOM( currentRoom, y ) ( (ROOM_DATA *) ( currentRoom )->exit[ ( y ) ]->to_room )
    // */
    ///*#define IS_CLOSED( currentRoom, y ) ( IS_SET( ( currentRoom )->exit[( y )]->exit_info, \
    //   EX_CLOSED))
    // */
    ///*#ifdef TRACK_THROUGH_DOORS
    //   #define VALID_EDGE( currentRoom, y ) \
    //   ( ( currentRoom )->exit[( y )] && \
    //   ( TOROOM(( currentRoom ), ( y ) ) != NOWHERE ) && \
    //   ( !IS_MARKED( TOROOM( ( currentRoom ), ( y ) ) ) ) )
    //   #else */
    ///*#define VALID_EDGE( currentRoom , y 
    //   ) \
    //   ( ( currentRoom )->exit[ ( y ) ] && \
    //   ( TOROOM( ( currentRoom ), ( y ) ) != NULL ) && \
    //   ( !IS_CLOSED( (currentRoom), ( y ) ) ) && \
    //   ( !IS_MARKED( TOROOM( ( currentRoom ), ( y ) ) ) ) ) */
    ///* #endif */
    //void 
    //list_enqueue (ROOM_DATA * currentRoom)
    //{
    //  static struct room_list_struct *curr;
    //  curr = new room_list_struct;
    //  curr->currentRoom = currentRoom;
    //  curr->next = NULL;
    //  if (list_tail != NULL)
    //    {
    //      list_tail->next = curr;
    //      list_tail = curr;
    //    }
    //  else
    //    list_head = list_tail = curr;
    //  return;
    //}

    //void 
    //bfs_enqueue (ROOM_DATA * currentRoom, short moveDirection, short depth)
    //{
    //  struct bfs_queue_struct *curr;
    //  curr = new bfs_queue_struct;
    //  curr->currentRoom = currentRoom;
    //  curr->moveDirection = moveDirection;
    //  curr->depth = depth + 1;
    //  curr->next = NULL;
    //  if (queue_tail != NULL)
    //    {
    //      queue_tail->next = curr;
    //      queue_tail = curr;
    //    }
    //  else
    //    queue_head = queue_tail = curr;
    //  list_enqueue (currentRoom);
    //  return;
    //}

    //void 
    //bfs_dequeue (void)
    //{
    //  struct bfs_queue_struct *curr;
    //  curr = queue_head;
    //  if ((queue_head = queue_head->next) == NULL)
    //    queue_tail = NULL;
    //  delete curr;
    //  return;
    //}

    //void 
    //list_dequeue (void)
    //{
    //  struct room_list_struct *curr;
    //  curr = list_head;
    //  if ((list_head = list_head->next) == NULL)
    //    list_tail = NULL;
    //  if (curr->currentRoom != NULL)
    //    {
    //      UNMARK (curr->currentRoom);
    //      delete curr;
    //    }
    //  return;
    //}

    //void 
    //bfs_clear_queue (void)
    //{
    //  while (queue_head != NULL)
    //    bfs_dequeue ();
    //  return;
    //}

    //void 
    //list_clear_queue (void)
    //{
    //  while (list_head != NULL)
    //    list_dequeue ();
    //}

    //int 
    //find_first_step (ROOM_DATA * src, ROOM_DATA * targetOfAction)
    //{
    //  int curr_dir;

    //  if (src == targetOfAction)
    //    return BFS_ALREADY_THERE;
    //  queue_head = queue_tail = NULL;
    //  list_head = list_tail = NULL;
    //  MARK (src);
    //  list_enqueue (src);
    //  for (curr_dir = 0; curr_dir < 6; curr_dir++)
    //    if (VALID_EDGE (src, curr_dir) &&
    //   !IS_SET (src->rmflags, ROOM_UNTRACKABLE))
    //      {
    //   MARK (TOROOM (src, curr_dir));
    //   bfs_enqueue (TOROOM (src, curr_dir), curr_dir, 0);
    //      }
    //  while (queue_head)
    //    {
    //      if (queue_head->depth >= (state_var_1 ? 90 : 15))
    //   {
    //     bfs_clear_queue ();
    //     list_clear_queue ();
    //     return BFS_NO_PATH;
    //   }
    //      if (queue_head->currentRoom == targetOfAction)
    //   {
    //     curr_dir = queue_head->moveDirection;
    //     bfs_clear_queue ();
    //     list_clear_queue ();
    //     return curr_dir;
    //   }
    //      else
    //   {
    //     for (curr_dir = 0; curr_dir < 6; curr_dir++)
    //       {
    //         if (VALID_EDGE (queue_head->currentRoom, curr_dir))
    //      {
    //        MARK (TOROOM (queue_head->currentRoom, curr_dir));
    //        bfs_enqueue (TOROOM (queue_head->currentRoom, curr_dir),
    //                queue_head->moveDirection, queue_head->depth);
    //      }
    //       }
    //     bfs_dequeue ();
    //   }
    //    }
    //  list_clear_queue ();
    //  return BFS_NO_PATH;
    //}


    //void 
    //do_track (CharacterData  chr, string szUserArguments)
    //{
    //  char arg[SML_LENGTH];
    //  CharacterData vict;
    //  DEFINE_COMMAND ("track", do_track, POSITION_STANDING, 0, NORMAL, "Allows you to search for trcks.  See help track for MoreRoomInfo info.")

    //    if (chr->position == POSITION_FIGHTING)
    //    return;
    //  if (IS_PLAYER (chr) && chr->pcdata->learned[gsn_track] < 3 && !is_member (chr, GUILD_RANGER))
    //    {
    //      send_to_char ("You really have no clue what you are doing. It would be helpful to\n\rlearn the TRACK skill first!\n\r", chr);
    //      return;
    //    }
    //  one_argy (szUserArguments, arg);
    //  if (arg[0] == '\0' && HUNTING (chr) == NULL)
    //    {
    //      send_to_char ("Whom are you trying to track?\n\r", chr);
    //      if (IS_PLAYER (chr))
    //   {
    //     chr->pcdata->voting_on = 0;
    //   }
    //      return;
    //    }
    //  if (arg[0] == '\0' && HUNTING (chr) != NULL)
    //    {
    //      do_track (chr, "continue");
    //      if (IS_PLAYER (chr))
    //   {
    //     chr->pcdata->voting_on = 0;
    //   }
    //      return;
    //    }
    //  if (strcmp (arg, "continue"))
    //    {
    //      if ((vict = get_char_world (chr, arg)) == NULL)
    //   {
    //     if (!str_cmp (arg, NAME (chr)))
    //       {
    //         send_to_char ("Strange... the trcks seem to end right here.\n\r", chr);
    //         if (HUNTING (chr) != NULL)
    //      {
    //        free_string (chr->fightInfoInternal->rgHunting);
    //        chr->fightInfoInternal->rgHunting = NULL;
    //      }
    //         if (IS_PLAYER (chr))
    //      {
    //        chr->pcdata->voting_on = 0;
    //      }
    //         return;
    //       }
    //     if (HUNTING (chr) != NULL)
    //       {
    //         send_to_char (
    //              "GeneralTypeOfEffect TRACK and your name to stop tracking your quarry.\n\r", chr);
    //         if (IS_PLAYER (chr))
    //      {
    //        chr->pcdata->voting_on = 0;
    //      }
    //         return;
    //       }

    //     send_to_char ("You begin to look for trcks...\n\r", chr);
    //     if (HUNTING (chr) == NULL)
    //       {
    //         check_fgt (chr);
    //         if (strlen (arg) < 16)
    //      chr->fightInfoInternal->rgHunting = str_dup (arg);
    //       }
    //     if (IS_PLAYER (chr))
    //       {
    //         chr->pcdata->tickcounts = 9;
    //         chr->pcdata->voting_on = 999;
    //       }
    //     return;
    //   }

    //      if (chr != vict && HUNTING (chr) != NULL)
    //   {
    //     send_to_char (
    //     "GeneralTypeOfEffect TRACK and your name to stop tracking your quarry.\n\r", chr);
    //     if (IS_PLAYER (chr))
    //       {
    //         chr->pcdata->voting_on = 0;
    //       }
    //     return;
    //   }
    //      if (chr == vict)
    //   {
    //     send_to_char ("Strange... the trcks seem to end right here.\n\r", chr);
    //     if (HUNTING (chr) != NULL)
    //       {
    //         free_string (chr->fightInfoInternal->rgHunting);
    //         chr->fightInfoInternal->rgHunting = NULL;
    //       }
    //     if (IS_PLAYER (chr))
    //       {
    //         chr->pcdata->voting_on = 0;
    //       }
    //     return;
    //   }
    //    }
    //  else
    //    {
    //      if (HUNTING (chr) == NULL)
    //   {
    //     send_to_char ("You aren't tracking anyone.\n\r", chr);
    //     if (IS_PLAYER (chr))
    //       {
    //         chr->pcdata->voting_on = 0;
    //       }
    //     return;
    //   }
    //      if ((vict = get_char_world (chr, HUNTING (chr))) == NULL)
    //   {
    ///*      send_to_char("You find some footprints of some sort, but aren't good enough to determine\n\r",chr);
    //   send_to_char("if they are your victim's, how old they are, or where they lead...\n\r",chr);
    //   if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   }
    //   if (IS_PLAYER(chr)) 
    //   {
    //   chr->pcdata->voting_on=0;
    //   }
    //   return; */
    //   }
    //    }
    //  send_to_char ("You begin to look for trcks...\n\r", chr);
    //  if (HUNTING (chr) == NULL)
    //    {
    //      check_fgt (chr);
    //      if (strlen (arg) < 16)
    //   chr->fightInfoInternal->rgHunting = str_dup (arg);
    //    }
    //  if (IS_PLAYER (chr))
    //    {
    //      chr->pcdata->tickcounts = 9;
    //      chr->pcdata->voting_on = 999;
    //    }
    //  return;
    //}

    //void 
    //do_track_t (CharacterData  chr, string szUserArguments)
    //{
    //  char buf[STD_LENGTH];
    //  char arg[STD_LENGTH];
    //  TRACK_DATA *tr;
    //  CharacterData vict;
    //  int moveDirection;
    //  if (chr->position == POSITION_FIGHTING)
    //    return;
    //  if (IS_PLAYER (chr) && chr->pcdata->learned[gsn_track] < 3 && !is_member (chr, GUILD_RANGER))
    //    {
    //      send_to_char ("You really have no clue what you are doing. It would be helpful to\n\rlearn the TRACK skill first!\n\r", chr);
    //      return;
    //    }
    ///* if( !can_use_skill( chr, gsn_track ) )
    //   {
    //   send_to_char( "You can't seem to find any trcks here.\n\r", chr );
    //   return;
    //   }
    // */
    //  one_argy (szUserArguments, arg);
    //  if (arg[0] == '\0' && HUNTING (chr) == NULL)
    //    {
    //      send_to_char ("Whom are you trying to track?\n\r", chr);
    //      return;
    //    }
    //  if (arg[0] == '\0' && HUNTING (chr) != NULL)
    //    {
    //      do_track (chr, "continue");
    //      return;
    //    }
    //  if (strcmp (arg, "continue"))
    //    {
    //      if ((vict = get_char_world (chr, arg)) == NULL)
    //   {
    //     send_to_char ("You find some footprints of some sort, but aren't good enough to determine\n\r", chr);
    //     send_to_char ("if they are your victim's, how old they are, or where they lead...\n\r", chr);
    ///*          if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   } */
    //     return;
    //   }
    //      if (chr == vict && HUNTING (chr) != NULL)
    //   {
    //     send_to_char ("You find some footprints of some sort, but aren't good enough to determine\n\r", chr);
    //     send_to_char ("if they are your victim's, how old they are, or where they lead...\n\r", chr);
    //     if (HUNTING (chr) != NULL)
    //       {
    //         free_string (chr->fightInfoInternal->rgHunting);
    //         chr->fightInfoInternal->rgHunting = NULL;
    //       }
    //     return;
    //   }
    //      if (chr != vict && HUNTING (chr) != NULL)
    //   {
    //     send_to_char (
    //     "GeneralTypeOfEffect TRACK and your name to stop tracking your quarry.\n\r", chr);
    //     return;
    //   }
    //    }
    //  else
    //    {
    //      if (HUNTING (chr) == NULL)
    //   {
    //     send_to_char ("You aren't tracking anyone.\n\r", chr);
    //     return;
    //   }
    //      if ((vict = get_char_world (chr, HUNTING (chr))) == NULL)
    //   {
    //     send_to_char ("You find some footprints of some sort, but aren't good enough to determine\n\r", chr);
    //     send_to_char ("if they are your victim's, how old they are, or where they lead...\n\r", chr);
    //     /*  if (HUNTING(chr)!=NULL) 
    //        {
    //        free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //        } */
    //     return;
    //   }
    //    }

    //  if (IS_PLAYER (chr) &&
    //      (chr->pcdata->learned[gsn_track] < number_range (0, 50) && !is_member (chr, GUILD_RANGER)))
    //    {
    //      send_to_char ("You find some footprints of some sort, but aren't good enough to determine\n\r", chr);
    //      send_to_char ("if they are your victim's, how old they are, or where they lead...\n\r", chr);
    ///*      if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   }
    //   if (IS_PLAYER(chr)) 
    //   {
    //   chr->pcdata->voting_on=0;
    //   } */
    //      return;
    //    }

    //  for (tr = chr->inRoom->trcks; tr != NULL; tr = tr->next_track_in_room)
    //    {
    //      if ((IS_PLAYER (tr->chr) && !str_cmp (HUNTING (chr), NAME (tr->chr))) ||
    //      (IS_MOB (tr->chr) && is_name (HUNTING (chr), tr->chr->pIndexData->name)))
    //   {
    //     if (tr->dir_left == 10 || tr->chr->GetInRoom() == chr->inRoom)
    //       {
    //         send_to_char ("Strange... the trcks seem to end right here.\n\r", chr);
    //         if (HUNTING (chr) != NULL)
    //      {
    //        free_string (chr->fightInfoInternal->rgHunting);
    //        chr->fightInfoInternal->rgHunting = NULL;
    //      }
    //         if (IS_PLAYER (chr))
    //      {
    //        chr->pcdata->voting_on = 0;
    //      }
    //         return;
    //       }

    //     moveDirection = tr->dir_came;
    //     if (moveDirection != 10)
    //       {
    //         if (moveDirection >= 4)
    //      sprintf (buf, "The trcks suggest that %s entered the area from %s.\n\r",
    //          SEX (tr->chr) == SEX_FEMALE ? "she" :
    //          (SEX (tr->chr) == SEX_MALE ? "he" : "it"),
    //          moveDirection == 4 ? "above" : "below");
    //         else
    //      sprintf (buf, "The trcks suggest that %s entered the area from the %s.\n\r",
    //          SEX (vict) == SEX_FEMALE ? "she" :
    //          (SEX (vict) == SEX_MALE ? "he" : "it"),
    //          dir_name[moveDirection]);
    //         send_to_char (buf, chr);
    //       }
    //     moveDirection = tr->dir_left;
    //     if (moveDirection >= 4)
    //       sprintf (buf, "%s trcks appear to leave the area right %s you!\n\r",
    //           SEX (tr->chr) == SEX_FEMALE ? "Her" :
    //           (SEX (tr->chr) == SEX_MALE ? "His" : "Its"),
    //           moveDirection == 4 ? "above" : "below");
    //     else
    //       sprintf (buf, "%s trcks appear to leave the area heading %s!\n\r",
    //           SEX (vict) == SEX_FEMALE ? "Her" :
    //           (SEX (vict) == SEX_MALE ? "His" : "Its"),
    //           dir_name[moveDirection]);
    //     send_to_char (buf, chr);
    //     if (HUNTING (chr) == NULL)
    //       {
    //         check_fgt (chr);
    //         if (strlen (arg) < 16)
    //      chr->fightInfoInternal->rgHunting = str_dup (arg);
    //       }
    //     if (IS_PLAYER (chr) && number_range (1, 3) == 2)
    //       skill_gain (chr, gsn_track, TRUE);
    //     return;
    //   }
    //    }

    //  send_to_char ("You find some footprints of some sort, but aren't good enough to determine\n\r", chr);
    //  send_to_char ("if they are your victim's, how old they are, or where they lead...\n\r", chr);



    ///*
    //   moveDirection = find_first_step( chr->inRoom, vict->inRoom );
    //   switch( moveDirection )
    //   {
    //   case BFS_ERROR:
    //   send_to_char("Hmm.. something seems to be wrong.\n\r", chr);
    //   if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   }
    //   break;
    //   case BFS_ALREADY_THERE:
    //   if( HUNTING(chr) == NULL )
    //   send_to_char("Hmm, the trcks seem to end right here.\n\r", chr);
    //   else
    //   send_to_char("You've found your quarry!\n\r", chr );
    //   if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   }
    //   if (IS_PLAYER(chr)) 
    //   {
    //   chr->pcdata->voting_on=0;
    //   }
    //   break;
    //   case BFS_NO_PATH:
    //   sprintf(buf, "You're unable to pick up trcks of %s.\n\r",
    //   vict->sex == SEX_FEMALE ? "her" : "him" );
    //   if (IS_PLAYER(chr)) 
    //   {
    //   chr->pcdata->voting_on=0;
    //   }
    //   send_to_char(buf, chr);
    //   if (HUNTING(chr)!=NULL) 
    //   {
    //   free_string(chr->fightInfoInternal->rgHunting); chr->fightInfoInternal->rgHunting=NULL;
    //   }
    //   break;
    //   default:
    //   if( IS_PLAYER(chr) &&
    //   (chr->pcdata->learned[gsn_track]<number_range(0,90) && !is_member(chr,GUILD_RANGER)))
    //   moveDirection = number_range( 0, 5 );
    //   if (IS_SET(vict->inRoom->rmflags,ROOM_UNTRACKABLE)) 
    //   {
    //   send_to_char("You are unable to tell which direction the trcks lead.\n\r",chr); return;
    //   }
    //   if ( moveDirection >= 4 )
    //   sprintf(buf, "You've picked up %s trcks leading %s you!\n\r",
    //   vict->sex == SEX_FEMALE ? "her" :
    //   (vict->sex == SEX_MALE ? "his" : "its" ),
    //   moveDirection == 4 ? "above" : "below" );
    //   else
    //   sprintf(buf, "You've picked up %s trcks leading %s of here!\n\r",
    //   vict->sex == SEX_FEMALE ? "her" :
    //   (vict->sex == SEX_MALE ? "his" : "its" ),
    //   dir_name[moveDirection]);
    //   send_to_char(buf, chr);
    //   if( HUNTING(chr) == NULL ) 
    //   {
    //   check_fgt(chr);
    //   if (strlen(arg)<16)
    //   chr->fightInfoInternal->rgHunting=str_dup( arg );
    //   }
    //   break;
    //   }
    // */
    //  return;
    //}

    //void 
    //hunt_victim (CharacterData  chr)
    //{
    //  char buf[STD_LENGTH];
    //  int moveDirection;
    //  CharacterData vict = NULL;
    //  if (chr == NULL || HUNTING (chr) == NULL)
    //    return;
    //  if (!IS_AWAKE (chr))
    //    return;
    //  if (!is_number (HUNTING (chr)))
    //    {
    //      /* make sure the char still exists */
    //      vict = get_char_world (chr, HUNTING (chr));
    //      if (vict == NULL)
    //   {
    //     /*sprintf(buf, "Damn! Lost the trail!" );
    //        do_say(chr, buf);
    //        chr->rgHunting[0] = '\0'; */
    //     return;
    //   }
    //      moveDirection = find_first_step (chr->inRoom, vict->inRoom);
    //    }
    //  else
    //    {
    //      state_var_1 = TRUE;
    //      moveDirection = find_first_step (chr->inRoom, get_room_index (atoi (HUNTING (chr))));
    //      state_var_1 = FALSE;
    //    }
    //  if (moveDirection < 0)
    //    {
    //      return;
    //    }
    //  else
    //    {
    //      if (!chr->inRoom->exit[moveDirection]) return;
    //      if (!chr->inRoom->exit[moveDirection]->to_room) return; // (ROOM_DATA *) 	
    //      if (!is_number (HUNTING (chr)) && chr->inRoom->exit[moveDirection] && (ROOM_DATA *) chr->inRoom->exit[moveDirection]->to_room &&
    //     chr->inRoom->area != ((ROOM_DATA *) chr->inRoom->exit[moveDirection]->to_room)->area)
    //   return;
    //      if (chr->inRoom && chr->inRoom->exit[moveDirection] && chr->inRoom->exit[moveDirection]->d_info &&
    //     IS_SET (chr->inRoom->exit[moveDirection]->d_info->exit_info, EX_CLOSED) &&
    //     IS_SET (chr->inRoom->exit[moveDirection]->d_info->exit_info, EX_ISDOOR) &&
    //     !IS_SET (chr->inRoom->exit[moveDirection]->d_info->exit_info, EX_LOCKED) &&
    //     !IS_SET (chr->inRoom->exit[moveDirection]->d_info->exit_info, EX_HIDDEN))
    //   {
    //     do_open (chr, chr->inRoom->exit[moveDirection]->d_info->keyword);
    //   }
    //      move_char (chr, moveDirection);
    //      if (is_number (HUNTING (chr)) && chr->inRoom->vnumClan == atoi (HUNTING (chr)))
    //   {
    //     if (HUNTING (chr) != NULL)
    //       {
    //         free_string (chr->fightInfoInternal->rgHunting);
    //         chr->fightInfoInternal->rgHunting = NULL;
    //       }
    //     return;
    //   }
    //      if (!is_number (HUNTING (chr)) && chr->GetInRoom() == vict->inRoom)
    //   {
    //     if (MASTER (chr) == vict)
    //       {
    //         if (chr->fightInfoInternal && chr->fightInfoInternal->rgHunting)
    //      {
    //        free_string (chr->fightInfoInternal->rgHunting);
    //        chr->fightInfoInternal->rgHunting = NULL;
    //      }
    //         return;
    //       }
    //     if (IS_MOB (chr) && IS_MOB (vict) && !IS_SET (chr->pcdata->act3, ACT3_MUTE) &&
    //         !is_safe (chr, vict))
    //       {
    //         sprintf (buf, "%s! You can run, but you can't hide!", NAME (vict));
    //         do_yell (chr, buf);
    //       }
    //     multi_hit (chr, vict, TYPE_UNDEFINED);
    //   }
    //      return;
    //    }
    //  return;
    //}


    public class Cmds
    {
        public static string do_quit(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            // Check quit conditions here
            if (!ch.SaveCharToDisk())
            {
                EmlenMud.LogError("Failed to save character " + ch.Name + " to disk!", null, LogType.Always);
            }
            ch.send_to_char("Leaving the game.");
            ch.ForceRemoveFromRoom("leaves the game", GeneralDirection.Max);
            List<CharacterData> rgchr = EmlenMud.DynamicWorld.AllChars1[ch.ShortName.ToString()];
            rgchr.Remove(ch);
            int nHash = StaticHelpers.FirstTwoLettersHash(ch.ShortName);
            List<CharacterData> rgchr2 = EmlenMud.DynamicWorld.AllCharsByFirstTwoLetters1[nHash];
            rgchr2.Remove(ch);
            if (ch.IsPlayer)
            {
                EmlenMud.DynamicWorld.AllPlayers1.Remove(ch);
            }
#if NO_SILVERLIGHT
            IDescriptorData dd = ch.descriptor;
            dd.character = null;
            if (EmlenMud.hostWebEngine != null)
            {
                EmlenMud.hostWebEngine.QuittingGame(dd);
            }
            else
            {
                dd.ConnectionNeedsClosing = true;
            }
#endif
            return "";
        }

        public static string view_area(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            // No arguments supported yet.. just the current area...
            RoomData room = EmlenMud.GetInRoom(ch);
            MemoryStream ms = new MemoryStream(100000);
            StreamWriter sw = new StreamWriter(ms);
            EmlenMud.OldschoolArea.SaveSingleArea(sw, room.area,
              EmlenMud.OldschoolRoom, EmlenMud.OldschoolMP,
              EmlenMud.OldschoolOP);
            sw.Flush();
            byte[] rgBytes = ms.ToArray();
#if NO_SILVERLIGHT
            string sz = "||a" + System.Text.Encoding.UTF8.GetString(rgBytes);
#else
            string sz = string.Empty;
#endif
            return sz;
        }

        public static string do_follow(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments.Length < 1 || szUserArguments.Equals("self", StringComparison.OrdinalIgnoreCase) == true)
            {
                if (ch.FollowingCharacter == null) return "You are not currently following anyone...";
                else
                {
                    ch.FollowingCharacter = null;
                    return "\n\r";
                }
            }

            CharacterData chToFollow = FindCharInRoomUsingDigitNameKeywordOrPrefix((CharacterData)ch, szUserArguments);

            if (chToFollow == null)
            {
                return "Follow what or whom?";
            }

            ch.FollowingCharacter = chToFollow;
            return "\n\r";
        }

        public static string do_autoassist(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments.Length < 1 || szUserArguments.Equals("self", StringComparison.OrdinalIgnoreCase) == true)
            {
                if (ch.Master == null) return "You are not currently set to assist anyone...";
                else
                {
                    ch.Master = null;
                    return "You will no longer auto-assist anyone in combat.";
                }
            }

            CharacterData chToAssist = FindCharInRoomUsingDigitNameKeywordOrPrefix((CharacterData)ch, szUserArguments);

            if (chToAssist == null)
            {
                return "Assist what or whom?";
            }

            ch.Master = chToAssist;
            return "You will now assist " + EmlenMud.ShortName(ch, chToAssist) + " in combat.";
        }

        public static CharacterData FindCharInRoomUsingDigitNameKeywordOrPrefix(CharacterData ch, string sz)
        {
            bool fUseNumber = true;

            for (int i = 0; i < sz.Length; i++)
            {
                if (!char.IsDigit(sz[i]))
                {
                    fUseNumber = false;
                    break;
                }
            }

            if (fUseNumber == true)
            {
                int nCharNum = 0;
                try
                {
                    nCharNum = Convert.ToInt32(sz);
                }
                catch
                {
                    nCharNum = 0;
                }
                return (CharacterData)ch.FindCharacterInRoomByNumber(nCharNum, EmlenMud.GetInRoom(ch), false);
            }

            CharacterData chFound = (CharacterData)EmlenMud.GetInRoom(ch).FindCharacterInRoom(sz);
            if (!ch.CanSee(chFound)) return null;
            return chFound;
        }

        public static string do_attack(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments.Length < 1) return "Attack what or whom?";

            CharacterData chToAttack = FindCharInRoomUsingDigitNameKeywordOrPrefix((CharacterData)ch, szUserArguments);

            if (chToAttack == null)
            {
                return "Attack what or whom?";
            }

            if (ch.CanAttackChar(chToAttack) == false) return ch.ReasonCantAttackChar(chToAttack);
            ch.AttackingCharacter = chToAttack;
            return "You begin attacking " + EmlenMud.ShortName(ch, chToAttack) + "!";
        }

        public static string do_announce(CharacterData ch, string presetFirstArgument, string szUserArguments, bool fUseSomeoneText, bool fUseSForPlural)
        {
            string szTo = "0";
            string szColorCodeBegin = "{Y}";
            string szColorCodeAnnouncement = "";
            string szColorCodeAnnouncementText = "";
            string szAnnounceSymbol = ", ";
            string szAnnouncementName = "announce";


            string[] rgGetChannelInfo = null;
            if (!string.IsNullOrEmpty(presetFirstArgument))
            {
                rgGetChannelInfo = presetFirstArgument.Split("|".ToCharArray(), StringSplitOptions.None);
                if (rgGetChannelInfo != null)
                {
                    if (rgGetChannelInfo.Length > 0) szTo = rgGetChannelInfo[0];
                    if (rgGetChannelInfo.Length > 1) szColorCodeBegin = rgGetChannelInfo[1];
                    if (rgGetChannelInfo.Length > 2) szColorCodeAnnouncement = rgGetChannelInfo[2];
                    if (rgGetChannelInfo.Length > 3) szColorCodeAnnouncementText = rgGetChannelInfo[3];
                    if (rgGetChannelInfo.Length > 4) szAnnounceSymbol = rgGetChannelInfo[4];
                    if (rgGetChannelInfo.Length > 5) szAnnouncementName = rgGetChannelInfo[5];
                }
            }

            if (StaticHelpers.Empty(szUserArguments, true)) return StaticHelpers.FirstLetterCap(szAnnouncementName) + " what?";
            int nMinLevel = Convert.ToInt32(szTo);
            string szS = (fUseSForPlural ? "s" : "");

            for (int i = 0; i < EmlenMud.DynamicWorld.AllPlayers1.Count; i++)
            {
                CharacterData chTo = (CharacterData)EmlenMud.DynamicWorld.AllPlayers1[i];

                if (chTo == ch) continue;
                if (chTo.Level < nMinLevel) continue;

                string szAnnouncerName = "";

                if (!chTo.CanSee(ch))
                {
                    if (!fUseSomeoneText) continue;
                    szAnnouncerName = "Someone";
                }
                else
                {
                    szAnnouncerName = EmlenMud.ShortName(chTo, ch);
                }

                chTo.send_to_char(szColorCodeBegin + szAnnouncerName + " " + szColorCodeAnnouncementText +
                  szAnnouncementName + szS + szAnnounceSymbol + szColorCodeAnnouncement +
                "'" + szUserArguments + "'");
            }

            return szColorCodeBegin + "You " + szColorCodeAnnouncementText +
              szAnnouncementName + szAnnounceSymbol + szColorCodeAnnouncement +
              "'" + szUserArguments + "'";
        }

        public static string do_announce_to_only_those_who_can_see(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            return do_announce(ch, presetFirstArgument, szUserArguments, false, true);
        }

        public static string do_announce_use_someone_text(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            return do_announce(ch, presetFirstArgument, szUserArguments, true, true);
        }

        public enum RequestReflectedTypes
        {
            None = 0,
            Class = 1,
            Member = 1 << 1,
            Enum = 1 << 2,
            Properties = 1 << 3,
            Methods = 1 << 4,
            Interfaces = 1 << 5,
            BaseClasses = 1 << 6
        }

        public static bool IsWantedType(RequestReflectedTypes reflectedType, RequestReflectedTypes wants)
        {
            return ((reflectedType & wants) != 0);
        }

        public static string do_list_reflectedTypes(CharacterData ch, RequestReflectedTypes typesToShow, string specificTypeName, bool fDetails)
        {
            // HEREHERE ABCABC
            StringBuilder sb = new StringBuilder(30000);
            string szSpecified = specificTypeName == "" ? "" : specificTypeName.ToUpper();

            Type[] rgTypes = Assembly.GetExecutingAssembly().GetTypes();

            for (int i = 0; i < rgTypes.Length; i++)
            {
                if (rgTypes[i].IsClass == true && IsWantedType(RequestReflectedTypes.Class, typesToShow))
                {
                    sb.Append("[Class:"); sb.Append(rgTypes[i].FullName);
                    if (IsWantedType(RequestReflectedTypes.BaseClasses, typesToShow))
                    {
                        Type typ = rgTypes[i].BaseType;
                        while (typ.Equals(typeof(object)) == false)
                        {
                            sb.Append(" : ");
                            sb.Append(typ.FullName);
                            typ = typ.BaseType;
                        }
                    }
                    sb.Append("] ");
                }
                else if (rgTypes[i].IsEnum == true && IsWantedType(RequestReflectedTypes.Enum, typesToShow))
                {
                    sb.Append("[Enum"); sb.Append(rgTypes[i].FullName);
                    if (rgTypes[i].GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
                    {
                        sb.Append("(Flags): ");
                    }
                    else { sb.Append(": "); }
                    //FieldInfo[] fields = rgTypes[i].GetFields();
                    //foreach (FieldInfo field in fields)
#if NO_SILVERLIGHT
                    string[] rgsz = Enum.GetNames(rgTypes[i]);
                    for (int n = 0; n < rgsz.Length; n++)
                    {
                        sb.Append(rgsz[n] + ", ");
                    }
                    sb.Remove(sb.Length - 2, 2);
#endif
                    sb.Append("] \n");
                }
            }

            return sb.ToString();
        }

        public static string do_list_typeInfo(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (presetFirstArgument.Equals("enums", StringComparison.Ordinal) == true)
            {
                return do_list_reflectedTypes(ch, RequestReflectedTypes.Enum, szUserArguments == "enums" ? "" : szUserArguments, true);
            }
            else if (presetFirstArgument.Equals("classes", StringComparison.Ordinal) == true)
            {
                return do_list_reflectedTypes(ch, RequestReflectedTypes.Class | RequestReflectedTypes.BaseClasses, szUserArguments == "classes" ? "" : szUserArguments, true);
            }
            else
            {
                // MoreRoomInfo here
                return "";
            }
        }

        public static string do_tell(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (presetFirstArgument == "")
            {
                // Standard tell <char> (something)
                int nLoc = szUserArguments.IndexOf(' ');
                if (nLoc <= 0) return "Tell what to whom?";
                // Need to take into account what the talking char looks like to the
                // other character, or even if they can talk...			
                string[] rgTwoParts = szUserArguments.Split(" ".ToCharArray(), 2, StringSplitOptions.None);
                if (rgTwoParts.Length < 2) return "Tell what to whom?";
                CharacterData chrTo = (CharacterData)ch.FindCharacterInGame(rgTwoParts[0], true);
                if (chrTo == null) return "Unable to find that character...";
                chrTo.send_to_char(EmlenMud.ShortName(chrTo, ch) + " tells you, {G}'" + rgTwoParts[1] + "'");
                return "You tell " + EmlenMud.ShortName(ch, chrTo) + ", {G}'" + rgTwoParts[1] + "'";
            }
            // can do group tell here, etc
            return "";
        }

        public static string do_say(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (AssertRoomShouldExist(ch, EmlenMud.GetInRoom(ch)) == false) return "Not in any room!";
            if (presetFirstArgument.Equals("room", StringComparison.OrdinalIgnoreCase) == true)
            {
                EmlenMud.SendToOthersWhoCanSee(ch, EmlenMud.GetInRoom(ch), "|ShortName says, {W}'" + szUserArguments + "'");
                return "You say, {W}'" + szUserArguments + "'";
            }
            else if (presetFirstArgument.Equals("area", StringComparison.OrdinalIgnoreCase) == true)
            {
                // TODO: area say, world say, etc...
            }

            return "";
        }


        public static bool AssertRoomShouldExist(CharacterData ch, RoomData room)
        {
            if (room == null)
            {
                EmlenMud.LogError("Character " + ch.Name + " (" + ch.MobOrPlayer + ") was not in any room, internal room vnum = " + ch.vnumInRoom.ToString(), null, LogType.WorldError);
                return false;
            }
            return true;
        }

        private static string move(CharacterData ch, RoomData currentRoom, GeneralDirection moveDirection)
        {
            if (AssertRoomShouldExist(ch, currentRoom) == false) return "Not in any room!";
            ExitData ex = currentRoom[moveDirection];
            if (ex == null) return "You can't " + ch.GetSingularMovementDescription() + " " + Enum.GetName(typeof(GeneralDirection), moveDirection) + " from here.";
            //if (ex.EmlenMud == null) ex.AssignEmlenMud(ch.EmlenMud);
            RoomData roomTo = (RoomData)ex.to_room;
            if (roomTo == null)
            {
                EmlenMud.LogError("Character " + ch.Name + " (" + ch.MobOrPlayer + ") was not able to move " + Enum.GetName(typeof(GeneralDirection), moveDirection) + " from room vnum " + ch.vnumInRoom.ToString() + " into room vnum " + ex.Vnum.ToString(), null, LogType.WorldError);
                return "The room you are trying to " + ch.GetSingularMovementDescription() + " to does not exist!";
            }
            if (ex.D_info != null)
            {
                if (ch.CanSee((DoorData)ex.D_info) == false)
                {
                    return "You can't " + ch.GetSingularMovementDescription() + " " + moveDirection.ToString() + " from here.";
                }
                if ((ex.D_info.Exit_info & ExitFlags.CLOSED) != 0 && ch.HolyWalk == false)
                {
                    return "The " + ex.D_info.DoorName + " is closed.";
                }
            }
            List<CharacterData> rgAttackers = ch.WhoIsCurrentlyAttackingThisCharacter;
            if (rgAttackers.Count > 0) return "You are currently being attacked!  Try the 'flee' command if you wish to flee combat.";
            List<CharacterData> rgFollowers = ch.GetFollowers(currentRoom);

            if (ch.IsAuthorizedToBeInRoom(roomTo) == false) return ch.ReasonIsNotAuthorizedToBeInRoom(roomTo);
            GeneralDirection reverseDir = StaticHelpers.ReverseDirectionOf(moveDirection);

            // Other conditions here -- chAttacking, etc
            if (ch.ForceRemoveFromRoom(ch.GetPluralMovementDescription(), moveDirection) == false) return "You aren't able to leave the current room at the moment!";
            if (ch.ForceMoveToRoom(roomTo, currentRoom, ch.GetPluralMovementDescriptionSeenbyOthers(), reverseDir) == false)
            {
                // put back in the original currentRoom
                ch.ForceMoveToRoom(currentRoom, null, null, GeneralDirection.Max);
                return "You weren't able to " + ch.GetSingularMovementDescription() + " to that room.";
            }
            ch.send_to_char("You " + ch.GetSingularMovementDescription() + " " + moveDirection.ToString() + ".");
            // Handle tag-alongs
            for (int i = 0; i < rgFollowers.Count; i++)
            {
                CharacterData chFollower = (CharacterData)rgFollowers[i];
                move(chFollower, currentRoom, moveDirection);
            }
            ch.LastMovementTime = EmlenMud.DynamicWorld.CurrentTime.dt;
            return roomTo.HowRoomLooksTo(ch).ToString();
        }

        public static bool CheckOrQueueMovement(CharacterData ch, string szCmd)
        {
            TimeSpan ts = EmlenMud.DynamicWorld.CurrentTime.dt.Subtract(ch.LastMovementTime);
            if (ts.TotalSeconds < GameTiming.SecondsPerMove) { ch.EnqueueMovementCommand(szCmd); return false; }
            return true;
        }
        public static string do_north(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (CheckOrQueueMovement(ch, "north") == false) return "";
            else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.N);
        }

        public static string do_south(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (CheckOrQueueMovement(ch, "south") == false) return "";
            else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.S);
        }

        public static string do_west(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (CheckOrQueueMovement(ch, "west") == false) return "";
            else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.W);
        }

        public static string do_east(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (CheckOrQueueMovement(ch, "east") == false) return "";
            else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.E);
        }

        public static string do_down(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            // TODO
            //if (CheckOrQueueMovement(ch, "down") == false) return "";
            //else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.down);
            return string.Empty;
        }

        public static string do_up(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            // TODO
            //if (CheckOrQueueMovement(ch, "up") == false) return "";
            //else return move(ch, EmlenMud.GetInRoom(ch), GeneralDirection.up);
            return string.Empty;
        }

        public static string GoToRoom(CharacterData ch, int vnum)
        {
            RoomData room = EmlenMud.WorldTemplates.GetRoom(vnum);
            if (room == null)
            {
                return "Location not found.";
            }
            if (ch.IsAuthorizedToBeInRoom(room) == false)
                return "You are not authorized to go to that location.";

            EmlenMud.RemoveCharacterFromRoom(ch, EmlenMud.GetInRoom(ch));
            if (!EmlenMud.AddCharacterToRoom(ch, room))
            {
                EmlenMud.SetInRoom(ch, room);
            }
            return do_look(ch, "", "");
        }

        public static RoomData FindObjRoom(ObjectData obj)
        {
            if (obj.in_room != null) return obj.in_room;
            if (obj.Carried_by != null) return EmlenMud.GetInRoom(obj.Carried_by);
            if (obj.In_obj != null) return FindObjRoom(obj.In_obj);
            return null;
        }
        public static string do_goto(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            int vnum = 0;
            if (presetFirstArgument == "room")
            {
                try { vnum = Convert.ToInt32(szUserArguments); }
                catch { vnum = -1; }
                if (vnum != 0) return GoToRoom(ch, vnum);
            }
            if (vnum == -1 || presetFirstArgument == "player")
            {
                CharacterData plr = ch.FindCharacterInGame(szUserArguments, true);
                if (vnum == -1) vnum = -2;
                else return "Player not found in the game.";
            }
            string szMobName = "";
            if (vnum == -2 || presetFirstArgument == "mob")
            {
                try { vnum = Convert.ToInt32(szUserArguments); }
                catch { vnum = -3; }
                if (vnum > 0 &&
                  EmlenMud.WorldTemplates.AllMobPrototypes.ContainsKey(vnum))
                {
                    MobPrototype mp = EmlenMud.WorldTemplates.AllMobPrototypes[vnum];
                    szMobName = mp.ShortName;
                    CharacterData mob = ch.FindCharacterInGame(szMobName, false);
                    if (mob != null)
                    {
                        RoomData room = EmlenMud.GetInRoom(mob);
                        if (room != null) return GoToRoom(mob, room.VnumRoom);
                    }
                }
                if (presetFirstArgument == "mob")
                {
                    CharacterData mob = ch.FindCharacterInGame(szUserArguments, false);
                    if (mob != null)
                    {
                        RoomData room = EmlenMud.GetInRoom(mob);
                        if (room != null) return GoToRoom(ch, room.VnumRoom);
                    }
                }
            }
            if (vnum == -3 || presetFirstArgument == "object")
            {
                try { vnum = Convert.ToInt32(szUserArguments); }
                catch { vnum = -4; }
                if (vnum > 0 &&
                  EmlenMud.DynamicWorld.ObjectsByProtoVnum1.ContainsKey(vnum))
                {
                    List<ObjectData> rgObj = EmlenMud.DynamicWorld.ObjectsByProtoVnum1[vnum];
                    if (rgObj != null && rgObj.Count > 0)
                    {
                        ObjectData obj = rgObj[0];
                        RoomData room = FindObjRoom(obj);
                        if (room != null)
                        {
                            return GoToRoom(ch, room.VnumRoom);
                        }
                    }
                }
            }
            return "Not found in game.";
        }

        public static string ShowCurrentSettings(CharacterData ch)
        {
            StringBuilder sb = new StringBuilder(1024);
#if NO_SILVERLIGHT
            string[] rgsz = Enum.GetNames(typeof(PlayerSettings));

            for (int n = 0; n < rgsz.Length; n++)
            {
                sb.Append(rgsz[n].PadRight(20, '.'));
                long nSetting = (long)Enum.Parse(typeof(PlayerSettings), rgsz[n]);
                sb.AppendLine(ch.GetPlayerSetting((PlayerSettings)nSetting) ? "ON" : "OFF");
            }
            sb.AppendLine("To toggle a setting, type 'set <settingname> ON/OFF'");
#endif
            return sb.ToString();
        }

        public static string do_settings(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (string.IsNullOrEmpty(szUserArguments))
            {
                return ShowCurrentSettings(ch);
            }

            string[] rgsz = szUserArguments.Trim().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            string szSetting = "";
            string szSetTo = "toggle";
            if (rgsz.Length >= 1) szSetting = rgsz[0];
            if (rgsz.Length >= 2) szSetTo = rgsz[1];
            long nSetting = 0;
            try
            {
                nSetting = (long)Enum.Parse(typeof(PlayerSettings), szSetting, true);
            }
            catch
            {
                return ShowCurrentSettings(ch);
            }
            bool fPreference = StaticHelpers.YesNoOnOffTrueFalse(
              szUserArguments, !ch.GetPlayerSetting((PlayerSettings)nSetting));
            ch.SetPlayerSetting((PlayerSettings)nSetting, fPreference);
            return "{W}Player setting '" + szSetting + "' set to {C}" + StaticHelpers.GetOnOrOff(fPreference).ToUpper();
        }

        public static string ShowCombatSettings(CharacterData ch)
        {
            StringBuilder sb = new StringBuilder(1024);
#if NO_SILVERLIGHT
            string[] rgsz = Enum.GetNames(typeof(CombatSettings));

            for (int n = 0; n < rgsz.Length; n++)
            {
                sb.Append(rgsz[n].PadRight(20, '.'));
                long nSetting = (long)Enum.Parse(typeof(CombatSettings), rgsz[n]);
                sb.AppendLine(ch.IsFightOptionSet((CombatSettings)nSetting) ? "ON" : "OFF");
            }
            sb.AppendLine("To toggle a combat option, type 'combat <optionname> ON/OFF'");
#endif
            return sb.ToString();
        }

        public static string do_combat_settings(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (string.IsNullOrEmpty(szUserArguments))
            {
                return ShowCombatSettings(ch);
            }

            string[] rgsz = szUserArguments.Trim().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            string szSetting = "";
            string szSetTo = "toggle";
            if (rgsz.Length >= 1) szSetting = rgsz[0];
            if (rgsz.Length >= 2) szSetTo = rgsz[1];
            long nSetting = 0;
            try
            {
                nSetting = (long)Enum.Parse(typeof(CombatSettings), szSetting, true);
            }
            catch
            {
                return ShowCombatSettings(ch);
            }
            bool fPreference = StaticHelpers.YesNoOnOffTrueFalse(
              szUserArguments, !ch.IsFightOptionSet((CombatSettings)nSetting));
            ch.SetCombatOption((CombatSettings)nSetting, fPreference);
            return "{W}Combat setting '" + szSetting + "' set to {C}" + StaticHelpers.GetOnOrOff(fPreference).ToUpper();
        }

        public static string do_help(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments.Equals("all", StringComparison.OrdinalIgnoreCase) == true ||
                szUserArguments.Equals("allcommands", StringComparison.OrdinalIgnoreCase) == true)
            {
                StringBuilder sb = EmlenMud.ListAllCommandsWithDesc(ch);
                if (!szUserArguments.Equals("allcommands", StringComparison.OrdinalIgnoreCase))
                {
                    sb.AppendLine("For help on a specific topic, type HELP {W}" + ch.GetItalicsString("topicname") + ".");
                }
                return sb.ToString();
            }

            HelpData hlp = HelpData.FindHelpTopic(szUserArguments, ch.Level);
            if (hlp == null)
            {
                return "No help on that topic could be found.";
            }
            return hlp.HelpText;
        }

        public static string do_look(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (ch == null) return "No Character";
            RoomData room = EmlenMud.GetInRoom(ch);
            if (room == null) return "Not in any room";


            if ((int)ch.position < (int)CharPosition.sleeping)
                return "{W}You can't see anything but stars!";
            else if ((int)ch.position == (int)CharPosition.sleeping)
                return "{y}You can't see anything, you're sleeping!";
            else if (ch.CanSee() == false)
                return "{Y}You can't see anything -- you are blind!";

            StringBuilder sb = new StringBuilder(4096);
            if (szUserArguments == "")
            {
                sb.Append(room.HowRoomLooksTo(ch));
            }
            else
            {
                //bool fLookAt = false;
                //bool fLookIn = false;
                //bool fLookOut = false;

                if (szUserArguments.StartsWith("at ", StringComparison.OrdinalIgnoreCase) == true)
                {
                    //fLookAt = true;
                    szUserArguments = szUserArguments.Substring(3);
                }
                else if (szUserArguments.StartsWith("in ", StringComparison.OrdinalIgnoreCase) == true)
                {
                    //fLookIn = true;
                    szUserArguments = szUserArguments.Substring(3);
                }
                else if (szUserArguments.Equals("out", StringComparison.OrdinalIgnoreCase))
                {
                    //fLookOut = true;
                    if (EmlenMud.GetInRoom(ch).IsRoomFlagSet(RoomFlags.ISVEHICLE)) { }// NYI						
                }
                else
                {
                    for (int i = 0; i < (int)GeneralDirection.Max; i++)
                    {
                        GeneralDirection dir = (GeneralDirection)i;
                        if ((szUserArguments.Length == 1 && dir.ToString().StartsWith(szUserArguments, StringComparison.OrdinalIgnoreCase)) ||
                          (dir.ToString().Equals(szUserArguments, StringComparison.OrdinalIgnoreCase) == true))
                        {
                            sb.Append(ch.LookDirection(EmlenMud.GetInRoom(ch), dir));
                            return sb.ToString();
                        }
                    }
                }

                // argument specified... let's look for others in the currentRoom first
                // exact match checking first
                string compname = szUserArguments;
                CharacterData chrOther = (CharacterData)EmlenMud.GetInRoom(ch).FindCharacterInRoom(compname);

                if (chrOther != null)
                {
                    if (ch.CanSee(chrOther) == true)
                    {
                        // if char looks at self?  oh well.. just let em look for now
                        return EmlenMud.LookAt(ch, chrOther).ToString();
                    }
                }

                chrOther = (CharacterData)EmlenMud.GetInRoom(ch).FindCharacterInRoom(szUserArguments);
                if (chrOther != null)
                {
                    if (ch.CanSee(chrOther) == true)
                    {
                        // if char looks at self?  oh well.. just let em look for now
                        return EmlenMud.LookAt(ch, chrOther);
                    }
                }
            }

            return sb.ToString();
        }

        public static string set_fly(CharacterData ch, bool fWantsToFly)
        {
            if (fWantsToFly == true && !ch.CanFlyRightNow())
                return ch.ReasonCantFlyRightNow();
            else if (ch.Flying == false && fWantsToFly == true)
            {
                ch.Flying = fWantsToFly;
                EmlenMud.SendToOthersWhoCanSee(ch, EmlenMud.GetInRoom(ch), "|ShortName takes flight.");
                return "You begin flying.";
            }
            else if (ch.Flying == true && fWantsToFly == false)
            {
                ch.Flying = fWantsToFly;
                EmlenMud.SendToOthersWhoCanSee(ch, EmlenMud.GetInRoom(ch), "|ShortName lands.");
                return "You land.";
            }
            else if (ch.Flying == false && fWantsToFly == false)
                return "You are not flying.";
            else if (ch.Flying == true && fWantsToFly == true)
                return "You are already flying.";

            return "";
        }

        public static string do_land(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, false);
            return set_fly((CharacterData)ch, fPreference);
        }

        public static string do_fly(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, true);
            return set_fly((CharacterData)ch, fPreference);
        }

        public static string do_socials(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (szUserArguments.Equals("all", StringComparison.OrdinalIgnoreCase) == true)
                return EmlenMud.DisplayAllSocials(ch);
            else
                return "This command does not currently accept any user arguments.";
        }

        public static string do_autoexit(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = !ch.AutoExit;
            if (szUserArguments.Equals("toggle", StringComparison.OrdinalIgnoreCase) == false)
            {
                fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, fPreference);
            }
            ch.AutoExit = fPreference;
            return "Autoexit is now {Y}" + StaticHelpers.GetOnOrOff(ch.AutoExit).ToUpper() + "{w}.";
        }

        public static string do_holylight(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = !ch.HolyLight;
            if (szUserArguments.Equals("toggle", StringComparison.OrdinalIgnoreCase) == false)
            {
                fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, fPreference);
            }
            ch.HolyLight = fPreference;
            return "HolyLight is now {Y}" + StaticHelpers.GetOnOrOff(ch.HolyLight).ToUpper() + "{w}.";
        }

        public static string do_holypeace(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = !ch.HolyPeace;
            if (szUserArguments.Equals("toggle", StringComparison.OrdinalIgnoreCase) == false)
            {
                fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, fPreference);
            }
            ch.HolyPeace = fPreference;
            return "HolyPeace is now {Y}" + StaticHelpers.GetOnOrOff(ch.HolyPeace).ToUpper() + "{w}.";
        }

        public static string do_flee(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            // HEREHERE
            if (!ch.IsFighting) return "You are not currently fighting!";

            //  if (chr->ced && chr->ced->in_boat)
            //    {
            //      do_board (chr, "boat");
            //      return;
            //    }     

            if (ch.FightInfo.IsDelayed == true)
                return "You are too off balance from your last combat action to flee!";

            if (ch.IsPlayer && ch.IsDelayed)
                return "You fail to find a pause in combat in which to flee.";

            //bool double_flee = true;

            ch.AddDelayMilliseconds(2000.0);
            // How much was 10, exactly?
            //WAIT_STATE (chr, 10);

            if (ch.position == CharPosition.bashed)
                return "You try to crawl away, but you are bashed to the ground!\n\rBetter stand up first...";

            if (Rand.RandIntBetween(1, 100) < EmlenMud.WorldTemplates.pow.FleeChance)
                return "You couldn't manage to flee from combat!";


            //  if (performingCharacter.EmlenMud.GetInRoom(performingCharacter) && performingCharacter.EmlenMud.GetInRoom(performingCharacter).MoreRoomInfo && performingCharacter.EmlenMud.GetInRoom(performingCharacter).MoreRoomInfo.linkedTo)
            //    {
            //      if (number_range (1, 3) != 2)
            //   {
            //     send_to_char ("You couldn't manage to get out of the vehicle!\n\r", chr);
            //     return;
            //   }
            //      stop_fighting (chr, TRUE);
            //      NEW_POSITION(chr, POSITION_STANDING);
            //      send_to_char ("You managed to flee!\n\r", chr);
            //      do_leave (chr, "");
            //      return;
            //    }

            if (ch.position == CharPosition.groundfighting)
            {
                ch.send_to_char("You attempt to stand up...\n\r");
                return "STAND NOT IMPLEMENTED YET"; // do_stand(performingCharacter, "", "");
            }

            return "NYI";
            // HEREHERE: WORKING ON THIS

            //  if (IS_PLAYER (chr) && rchars_in_group (chr) > 1)
            //    double_flee = FALSE;
            //  was_in = performingCharacter.EmlenMud.GetInRoom(performingCharacter);
            //  for (attempt = 0; attempt < 6; attempt++)
            //    {
            //      EXIT_DATA *pexit;
            //      int door;
            //      door = number_door ();
            //      if ((pexit = was_in.exit[door]) == 0
            //     || (ROOM_DATA *) pexit.to_room == NULL
            //     || ((ROOM_DATA *) pexit.to_room).sectortyp == SECT_WATER_NOSWIM
            //     || ((ROOM_DATA *) pexit.to_room).sectortyp == SECT_WATER_SWIM
            //     || (pexit.d_info && IS_SET (pexit.d_info.exit_info, EX_CLOSED))
            //     || (IS_MOB (victim) && (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR)
            //       || (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR_EVIL)
            //           && IS_EVIL (chr))
            //       || (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR_GOOD)
            //           && !IS_EVIL (chr)))
            //         && victim.pIndexData && victim.pIndexData.mobGuards == door)
            //     || (IS_MOB (chr)
            //       && IS_SET (((ROOM_DATA *) pexit.to_room).rmflags, ROOM_NO_MOB)))
            //   continue;
            //      if (RIDING (chr) != NULL)
            //   {
            //     send_to_char ("You fall from your mount as you try to escape!\n\r", chr);
            //     check_fgt (performingCharacter.fightInfoInternal.chRiding);
            //     performingCharacter.fightInfoInternal.chRiding.fightInfoInternal.chMountedBy = NULL;
            //     performingCharacter.fightInfoInternal.chRiding = NULL;
            //   }
            //      if (MOUNTED_BY (chr) != NULL)
            //   {
            //     send_to_char ("Your rider falls off as you try to escape!\n\r", chr);
            //     send_to_char ("Your mount bolts from under you!\n\r", MOUNTED_BY (chr));
            //     check_fgt (performingCharacter.fightInfoInternal.chMountedBy);
            //     performingCharacter.fightInfoInternal.chMountedBy.fightInfoInternal.chRiding = NULL;
            //     performingCharacter.fightInfoInternal.chMountedBy = NULL;
            //   }
            //      move_char (chr, door + 20);
            //      if (IS_JAVA(chr)) do_clear(chr,"");
            //      if ((now_in = performingCharacter.EmlenMud.GetInRoom(performingCharacter)) == was_in)
            //   continue;
            //      performingCharacter.SetInRoom( was_in;
            //      sprintf (buf, "\x1B[1;32m%s flees %s in panic!\x1B[0m\n\r",
            //          capitalize (NAME (chr)),
            //          dir_name[door]);
            //      currentActionsAndBehavior (buf, chr, NULL, NULL, TO_ROOM);
            //      make_blood (chr, door);
            //      performingCharacter.SetInRoom( now_in;
            //      if (IS_PLAYER (chr))
            //   {
            //     fled_dir = door;
            //     was_in = performingCharacter.EmlenMud.GetInRoom(performingCharacter);
            //     for (tattempt = 0; tattempt < 6; tattempt++)
            //       {
            //         EXIT_DATA *tpexit;
            //         int tdoor;
            //         tdoor = number_door ();
            //         if ((tpexit = was_in.exit[tdoor]) == 0
            //        || (ROOM_DATA *) tpexit.to_room == NULL
            //        || ((ROOM_DATA *) tpexit.to_room).sectortyp == SECT_WATER_NOSWIM
            //        || ((ROOM_DATA *) tpexit.to_room).sectortyp == SECT_WATER_SWIM
            //        || (tpexit.d_info && IS_SET (tpexit.d_info.exit_info, EX_CLOSED))
            //        || (IS_MOB (victim) && (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR)
            //       || (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR_EVIL)
            //           && IS_EVIL (chr))
            //       || (IS_SET (victim.pIndexData.act3, ACT3_GUARD_DOOR_GOOD)
            //           && !IS_EVIL (chr)))
            //      && victim.pIndexData && victim.pIndexData.mobGuards == tdoor)
            //        || (IS_MOB (chr)
            //            && IS_SET (((ROOM_DATA *) tpexit.to_room).rmflags, ROOM_NO_MOB)))
            //      continue;
            //         if (fled_dir == rev_dir[tdoor])
            //      continue;
            //         if (double_flee)
            //      {
            //        move_char (chr, tdoor + 20);
            //      if (IS_JAVA(chr)) do_clear(chr,"");
            //        if ((now_in = performingCharacter.EmlenMud.GetInRoom(performingCharacter)) == was_in)
            //          continue;
            //      }
            //         break;
            //       }
            //     send_to_char ("Run away!  You flee head over heels!\n\r", chr);
            //     gain_exp (chr, -10);
            //   }
            //      if (FIGHTING (FIGHTING (chr)) == chr)
            //   stop_fighting (chr, TRUE);
            //      else
            //   stop_fighting (chr, FALSE);
            //      return;
            //    }
            //  currentActionsAndBehavior ("$N won't let you get away!", chr, NULL, FIGHTING (chr), TO_CHAR);
            //  return;
            //}

            //void
            //do_rescue (CharacterData  chr, string szUserArguments)
            //{
            //  char arg[SML_LENGTH];
            //  CharacterData victim;
            //  CharacterData fch;
            //  int temp;
            //  int temp2;
            //  DEFINE_COMMAND ("rescue", do_rescue, POSITION_FIGHTING, 0, NORMAL, "This command allows you to rescue someone getting whacked.  Success is based on your rescue skill.")

            //    one_argy (szUserArguments, arg);
            //  if (arg[0] == '\0')
            //    {
            //      send_to_char ("Who is that?\n\r", chr);
            //      return;
            //    }
            //  if ((victim = get_char_room (chr, arg)) == NULL)
            //    {
            //      send_to_char ("Who is that?\n\r", chr);
            //      return;
            //    }
            //  if ((IS_EVIL (chr) && !IS_EVIL (victim)) || (!IS_EVIL (chr) && IS_EVIL (victim)))
            //    {
            //      send_to_char ("Why would you want to do that?\n\r", chr);
            //      return;
            //    }
            //  if (performingCharacter.position != POSITION_STANDING && performingCharacter.position != POSITION_FIGHTING)
            //    {
            //      send_to_char ("You must be chAttacking or standing to rescue someone.\n\r", chr);
            //      return;
            //    }
            //  if (victim == chr)
            //    {
            //      send_to_char ("You rescue yourself.  That did a lot of good.\n\r", chr);
            //      return;
            //    }
            //  if (IS_PLAYER (chr) && IS_MOB (victim))
            //    {
            //      send_to_char ("That person doesn't want your help!\n\r", chr);
            //      return;
            //    }
            //  if (FIGHTING (chr) == victim)
            //    {
            //      send_to_char ("You rescue yourself.  That was useful.\n\r", chr);
            //      return;
            //    }
            //  if ((fch = FIGHTING (victim)) == NULL)
            //    {
            //      send_to_char ("That person is not chAttacking right now.\n\r", chr);
            //      return;
            //    }
            //  if (victim.position != POSITION_FIGHTING)
            //    {
            //      send_to_char ("That person isn't in a normal chAttacking position.\n\r", chr);
            //      return;
            //    }
            //  if (fch.position != POSITION_FIGHTING)
            //    {
            //      send_to_char ("That person's opponent is not in a normal chAttacking position!\n\r", chr);
            //      return;
            //    }
            //  if (victim.position == POSITION_GROUNDFIGHTING)
            //    {
            //      send_to_char ("That person is groundfighting! You can't rescue!\n\r", chr);
            //      return;
            //    }
            //#ifndef NEW_WORLD
            //  if (IN_BOAT (victim) && !IN_BOAT (chr))
            //    {
            //      send_to_char ("But that person is in a boat!\n\r", chr);
            //      return;
            //    }
            //  if (!IN_BOAT (victim) && IN_BOAT (chr))
            //    {
            //      send_to_char ("But that person is not in your boat!\n\r", chr);
            //      return;
            //    }
            //  if (IN_BOAT (victim) && IN_BOAT (chr) && performingCharacter.ced.in_boat != victim.ced.in_boat)
            //    {
            //      send_to_char ("But you aren't in the same boat!\n\r", chr);
            //      return;
            //    }
            //#endif
            //  if (victim.position == POSITION_GROUNDFIGHTING)
            //    {
            //      if (performingCharacter.position == POSITION_GROUNDFIGHTING)
            //   {
            //     send_to_char ("You are groundfighting! You can't rescue!\n\r", chr);
            //     return;
            //   }
            //      set_fighting (chr, FIGHTING (victim));
            //      return;
            //    }
            //  WAIT_STATE (chr, 15);
            //  if (IS_PLAYER (chr) && number_percent () > performingCharacter.pcdata.learned[gsn_rescue])
            //    {
            //      send_to_char ("You attempt the rescue but fail.\n\r", chr);
            //      return;
            //    }
            //  currentActionsAndBehavior ("You rescue $N!", chr, NULL, victim, TO_CHAR);
            //  currentActionsAndBehavior ("$n rescues you!", chr, NULL, victim, TO_VICT);
            //  currentActionsAndBehavior ("$n rescues $N!", chr, NULL, victim, TO_NOTVICT);
            //  check_fgt (fch);
            //  check_fgt (chr);
            //  check_fgt (victim);
            //  temp = victim.fightInfoInternal.combat_delay_count;
            //  temp2 = fch.fightInfoInternal.combat_delay_count;

            //  if (IS_PLAYER (chr))
            //    {
            //      stop_fighting (fch, FALSE);
            //      stop_fighting (victim, FALSE);
            //    }

            //  check_fgt (fch);
            //  check_fgt (victim);
            //  set_fighting (chr, fch);
            //  set_fighting (fch, chr);
            //  check_fgt (fch);
            //  check_fgt (victim);
            //  victim.fightInfoInternal.combat_delay_count = temp;
            //  fch.fightInfoInternal.combat_delay_count = temp2;
            //  WAIT_STATE (chr, 22);
            //  if (IS_PLAYER (chr)) {
            //    skill_gain (chr, gsn_rescue, TRUE);
            //  }
            //  victim.fightInfoInternal.combat_delay_count = temp;
            //  fch.fightInfoInternal.combat_delay_count = temp2;
            //  return;
            //}

        }

        public static string do_holywalk(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            bool fPreference = !ch.HolyWalk;
            if (szUserArguments.Equals("toggle", StringComparison.OrdinalIgnoreCase) == false)
            {
                fPreference = StaticHelpers.YesNoOnOffTrueFalse(szUserArguments, fPreference);
            }
            ch.HolyWalk = fPreference;
            return "HolyWalk is now {Y}" + StaticHelpers.GetOnOrOff(ch.HolyWalk).ToUpper() + "{w}.";
        }

        public static string do_wizinvis(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            int nInvisLevel = -1;
            try
            {
                nInvisLevel = Convert.ToInt32(szUserArguments.Trim());
            }
            catch { nInvisLevel = -1; }

            if (nInvisLevel < 0)
            {
                return "Please specify a Wizinvis level. Characters below this level will not be able to see you. Wizinvis 0 makes you visible to all players.";
            }
            else
            {
                ch.WizInvisLevel = nInvisLevel;
                if (nInvisLevel == 0)
                    return "{#22BB44}Wizinvis has been turned off.";
                else
                    return "{#22FF44}Your Wizinvis level has been set to " + ch.WizInvisLevel.ToString() + ".";
            }
        }

        public static string show_questflags(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            CharacterData vict = (CharacterData)ch.FindCharacterInGame(szUserArguments, true);
            if (vict == null || !vict.IsPlayer)
                return "That player was not found or is not online.\n\r";

            if (vict.pcdata.Queststages.Count == 0)
                return "That player has not yet started any quests.\n\r";

            StringBuilder sb = new StringBuilder(16000);
            foreach (var de in vict.pcdata.Queststages)
            {
                string szQuestName = (string)de.Key;
                int nStage = (int)de.Value;
                sb.AppendLine(szQuestName + " (" + nStage.ToString() + ")");
            }
            return sb.ToString();
        }

        public delegate bool FilterCharListDelegate(CharacterData chViewingList, CharacterData chInList);

        public static bool FilterShowInSameAreaOnly(CharacterData chViewingList, CharacterData chInList)
        {
            return true;
        }

        public static FilterCharListDelegate ShowInSameAreaOnly = FilterShowInSameAreaOnly;

        public static string showListOfCharacters(CharacterData ch, string szListTitle, List<CharacterData> rgChars, FilterCharListDelegate filterFunction)
        {
            StringBuilder sb = new StringBuilder(30000);
            bool fImmort = ch.Immortal;
            int i;
            if (!ch.IsUsingInterface(InterfaceType.HTML))
            {
                sb.Append("Name".PadRight(14, ' '));
                sb.Append("Status".PadLeft(12, ' '));
                sb.Append("Title".PadRight(20, ' '));
                if (fImmort == true)
                {
                    sb.Append("Location".PadRight(16, ' '));
                    sb.Append("Position".PadRight(16, ' '));
                    sb.Append("ID".PadLeft(10, ' '));
                    sb.Append("Vnum".PadLeft(10, ' '));
                }
                for (i = 0; i < rgChars.Count; i++)
                {
                    CharacterData chrInRoom = (CharacterData)rgChars[i];
                    if (ch.CanSee(chrInRoom) == false) continue;
                    if (filterFunction != null)
                    {
                        if (filterFunction.Invoke(ch, chrInRoom) == false) continue;
                    }
                    sb.Append(EmlenMud.ShortName(ch, chrInRoom).PadRight(14, ' '));
                    sb.Append(chrInRoom.IsLinkless ? "Not CurrentPlayerGameState".PadLeft(12, ' ') : "".PadLeft(12, ' '));
                    sb.Append(chrInRoom.Title);
                    if (fImmort == true)
                    {
                        if (EmlenMud.GetInRoom(chrInRoom) == null)
                            sb.Append("Missing room? (" + chrInRoom.vnumInRoom.ToString() + ")");
                        else
                            sb.Append(EmlenMud.GetInRoom(chrInRoom).Name + "(" + EmlenMud.GetInRoom(chrInRoom).VnumRoom.ToString() + ")");
                    }
                    if (fImmort == true)
                    {
                        sb.Append(StaticHelpers.FirstLetterCap(chrInRoom.position.ToString()));
                        sb.Append(chrInRoom.AssociatedID.ToString());
                        sb.Append((chrInRoom.IsMob == true) ? chrInRoom.mobPrototype.Vnum.ToString() : "");
                    }
                    sb.Append("\n\r");
                }
                sb.Append("{W}" + i.ToString() + " total");
                return sb.ToString();
            }

            //HtmlTable tbl = new System.Web.UI.HtmlControls.HtmlTable();
            //tbl.Width = "99%";
            //tbl.CellPadding = 2;
            //tbl.CellSpacing = 0;
            //tbl.Border = 0;
            //tbl.Style.Add(HtmlTextWriterStyle.BorderColor, "#BBDDFF");
            //tbl.Style.Add(HtmlTextWriterStyle.BorderStyle, "solid");
            //tbl.Style.Add(HtmlTextWriterStyle.BorderWidth, "2px");
            //HtmlTableRow HRow = new HtmlTableRow();
            //HRow.VAlign = "top";
            //HRow.Align = "left";
            //HRow.Style.Add(HtmlTextWriterStyle.FontWeight, "bold");
            //HRow.Style.Add(HtmlTextWriterStyle.Color, "#FFFFFF");
            //StaticHelpers.AddCell(HRow, "Name");
            //StaticHelpers.AddCell(HRow, "Title");
            //StaticHelpers.AddCell(HRow, "Status");
            //if (fImmort == true)
            //{
            //    StaticHelpers.AddCell(HRow, "Location");
            //    StaticHelpers.AddCell(HRow, "Position");
            //    StaticHelpers.AddCell(HRow, "ID");
            //    StaticHelpers.AddCell(HRow, "VNUM");
            //}
            //tbl.Rows.Add(HRow);

            //HtmlTableRow tr;
            //for (i = 0; i < rgChars.Count; i++)
            //{
            //    CharacterData chrInRoom = (CharacterData)rgChars[i];
            //    if (ch.CanSee(chrInRoom) == false) continue;
            //    if (filterFunction != null)
            //    {
            //        if (filterFunction.Invoke(ch, chrInRoom) == false) continue;
            //    }
            //    tr = new HtmlTableRow();
            //    tr.Style.Add(HtmlTextWriterStyle.Color, "#EFEFEF");
            //    tr.VAlign = "top";
            //    tr.Align = "left";
            //    StaticHelpers.AddCell(tr, chrInRoom.EmlenMud.ShortName(ch, chrInRoom));
            //    StaticHelpers.AddCell(tr, chrInRoom.Title);
            //    if (chrInRoom.IsLinkless)
            //    {
            //        StaticHelpers.AddCell(tr, "[Not CurrentPlayerGameState]");
            //    }
            //    else
            //    {
            //        StaticHelpers.AddCell(tr, "[]");
            //    }

            //    if (fImmort == true)
            //    {
            //        if (chrInRoom.EmlenMud.GetInRoom(chrInRoom) == null)
            //            StaticHelpers.AddCell(tr, "Missing room? (" + chrInRoom.vnumInRoom.ToString() + ")");
            //        else
            //            StaticHelpers.AddCell(tr, chrInRoom.EmlenMud.GetInRoom(chrInRoom).Name + "(" + chrInRoom.EmlenMud.GetInRoom(chrInRoom).VnumRoom.ToString() + ")");
            //    }
            //    if (fImmort == true) StaticHelpers.AddCell(tr, StaticHelpers.FirstLetterCap(chrInRoom.position.ToString()));
            //    if (fImmort == true) StaticHelpers.AddCell(tr, chrInRoom.ID.ToString());
            //    if (fImmort == true) StaticHelpers.AddCell(tr, (chrInRoom.IsMob == true) ? chrInRoom.mobPrototype.Vnum.ToString() : "");

            //    tbl.Rows.Add(tr);
            //}
            //tr = new HtmlTableRow();
            //StaticHelpers.AddCell(tr, "{W}" + i.ToString() + " total");
            //tbl.Rows.Add(tr);
            //StringWriter swriter = new StringWriter(sb);
            //System.Web.UI.HtmlTextWriter tw = new System.Web.UI.HtmlTextWriter(swriter);
            //tbl.RenderControl(tw);
            //tw.Flush();
            //sb = swriter.GetStringBuilder();
            //sb.Insert(0, "<center>" + (!StaticHelpers.Empty(szListTitle) ? ("<strong>" + szListTitle + "</strong>") : ""));
            //sb.Append("</center>");
            //sb.Replace("\n", "");
            //sb.Replace("\r", "");
            //string sz = sb.ToString();
            //tw.Close();
            //return sz;
            return string.Empty;
        }

        public static string do_list_all_chars(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            StringBuilder sb = new StringBuilder(64000);

            List<string> keys = EmlenMud.DynamicWorld.AllChars1.Keys;

            int nCount = keys.Count;
            string[] rgszTo = new string[nCount];
            keys.CopyTo(rgszTo, 0);
            List<CharacterData> rgAllChars = new
              List<CharacterData>(EmlenMud.DynamicWorld.AllPlayers1.Count +
              EmlenMud.DynamicWorld.WorldStats.Mobcount + 100);

            for (int i = 0; i < nCount; i++)
            {
                List<CharacterData> rgChrs;
                if (EmlenMud.DynamicWorld.AllChars1.TryGetValue(rgszTo[i], out rgChrs))
                {
                    for (int j = 0; j < rgChrs.Count; j++)
                    {
                        rgAllChars.Add(rgChrs[j]);
                    }
                }
            }
            return showListOfCharacters((CharacterData)ch, null, rgAllChars, null);
        }

        public static bool AssertAreaShouldExist(CharacterData ch, RoomData room, AreaData area)
        {
            if (area == null)
            {
                string szErr = "Room vnum " + room.VnumRoom.ToString() + " exists in an area " + room.Areastring + " which does not seem to exist!";
                if (ch != null) szErr = szErr + "  What's worse is that " + ch.MobOrPlayer + " is in that room...";
                EmlenMud.LogError(szErr, null, LogType.WorldError | LogType.Always);
                return false;
            }
            return true;
        }

        public static string do_who_area(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (!AssertRoomShouldExist(ch, EmlenMud.GetInRoom(ch))) return "You are not in any room.";
            if (!AssertAreaShouldExist(ch, EmlenMud.GetInRoom(ch), EmlenMud.GetInRoom(ch).area)) return "The room does not seem to be associated with an area.";
            AreaData area = EmlenMud.GetInRoom(ch).area;
            List<CharacterData> rgChars = new List<CharacterData>(200);
            for (int i = 0; i < area.RoomsInArea.Count; i++)
            {
                RoomData room = (RoomData)area.RoomsInArea[i];
                if (!room.HasCharacters) continue;
                for (int j = 0; j < room.characters.Count; j++)
                {
                    rgChars.Add((CharacterData)room.characters[j]);
                }
            }
            return showListOfCharacters((CharacterData)ch, "Characters in the Area", rgChars, null);
        }

        public static string do_who(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            return showListOfCharacters((CharacterData)ch, null, EmlenMud.DynamicWorld.AllPlayers1, null);
        }

        public static string do_test_command(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            return "The test was successful.";
        }

        public static string do_unlearn(CharacterData ch, string presetFirstArgument, string szUserArguments)
        {
            if (!ch.IsPlayer) return "";
            StringBuilder sb = new StringBuilder(1024);

            if (szUserArguments == "")
            {
                sb.AppendLine("Syntax is: Unlearn skill/spellname.");
                sb.AppendLine("Please note you do not get your practices or learns back.");
                sb.AppendLine("For a full reset (getting pracs and learns back), type preset.");
                return sb.ToString();
            }

            Spell spell = EmlenMud.FindSpell(szUserArguments, -1);
            if (spell == null)
                return "That isn't a valid skill or spell, sorry.";

            Object o = ch.pcdata.Learned[spell.Gsn];
            if (o == null)
            {
                sb.AppendLine("You haven't learned that skill/spell anyway!");
                sb.AppendLine("If it registers as a skill, you probably are wearing some +bonus equip.");
                return sb.ToString();
            }

            // Check for trying to unlearn prerequisites
            for (int i = 0; i < EmlenMud.WorldTemplates.SpellList.Count; i++)
            {
                Spell spl = (Spell)EmlenMud.WorldTemplates.SpellList[i];
                if (!string.IsNullOrEmpty(spl.Prereq1))
                    if (EmlenMud.FindSpell(spl.Prereq1) == spell)
                        return "You can not unlearn a prerequisite to a spell/skill you already know!";

                if (!string.IsNullOrEmpty(spl.Prereq2))
                    if (EmlenMud.FindSpell(spl.Prereq2) == spell)
                        return "You can not unlearn a prerequisite to a spell/skill you already know!";
            }

            ch.pcdata.Learned.Remove(spell.Gsn);
            sb.AppendLine("You have successfully unlearned " + spell.SecondaryName + ".");
            return sb.ToString();
        }
    }

    public static class GameTiming
    {
        public static double SecondsPerMove = 0.9;
        public static double SecondsBeforeConsideredLinkless = 30.0;
        public static double SecondsBetweenEachCombatRound = 1.6;
    }
}
